From 9b869230a724dc00ea21d00a222f4eb9396a385f Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Fri, 18 Dec 2009 09:35:57 -0800 Subject: s4 torture: Fix RAW-STREAMS-DELETE to pass against samba3 --- source4/torture/raw/streams.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/torture/raw/streams.c b/source4/torture/raw/streams.c index 79cacffe10..a55575b6a3 100644 --- a/source4/torture/raw/streams.c +++ b/source4/torture/raw/streams.c @@ -609,7 +609,8 @@ static bool test_stream_delete(struct torture_context *tctx, CHECK_STATUS(status, NT_STATUS_OK); /* w2k and w2k3 return 0 and w2k8 returns 1 */ - if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx)) { + if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx) || + TARGET_IS_SAMBA3(tctx)) { CHECK_VALUE(finfo.all_info.out.delete_pending, 0); } else { CHECK_VALUE(finfo.all_info.out.delete_pending, 1); -- cgit From daa561d75ba64f8034cd529243a4e71219b01c6f Mon Sep 17 00:00:00 2001 From: Zachary Loafman Date: Thu, 17 Dec 2009 22:32:58 +0000 Subject: s4 torture: Add test to show archive bit behavior with directories Signed-off-by: Tim Prouty --- source4/torture/raw/setfileinfo.c | 153 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) (limited to 'source4') diff --git a/source4/torture/raw/setfileinfo.c b/source4/torture/raw/setfileinfo.c index 42f4f320c2..1f8adfbe9a 100644 --- a/source4/torture/raw/setfileinfo.c +++ b/source4/torture/raw/setfileinfo.c @@ -970,6 +970,158 @@ done: return ret; } +static bool +torture_raw_sfileinfo_archive(struct torture_context *tctx, + struct smbcli_state *cli) +{ + const char *fname = BASEDIR "\\test_archive.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_setfileinfo sfinfo; + union smb_fileinfo finfo; + uint16_t fnum=0; + uint32_t access_mask = 0; + + if (!torture_setup_dir(cli, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli->tree, fname); + + /* + * create a normal file, verify archive bit + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid.fnum = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + io.ntcreatex.in.flags = 0; + status = smb_raw_open(cli->tree, tctx, &io); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "open failed"); + fnum = io.ntcreatex.out.file.fnum; + + torture_assert_int_equal(tctx, + io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, + FILE_ATTRIBUTE_ARCHIVE, + "archive bit not set"); + + /* + * try to turn off archive bit + */ + ZERO_STRUCT(sfinfo); + sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO; + sfinfo.generic.in.file.fnum = fnum; + sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; + status = smb_raw_setfileinfo(cli->tree, &sfinfo); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "setfileinfo failed"); + + finfo.generic.level = RAW_FILEINFO_ALL_INFO; + finfo.generic.in.file.fnum = fnum; + status = smb_raw_fileinfo(cli->tree, tctx, &finfo); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "fileinfo failed"); + + torture_assert_int_equal(tctx, + finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, + FILE_ATTRIBUTE_NORMAL, + "archive bit set"); + + status = smbcli_close(cli->tree, fnum); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "close failed"); + + status = smbcli_unlink(cli->tree, fname); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "unlink failed"); + + /* + * create a directory, verify no archive bit + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid.fnum = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_DIR_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; + io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + io.ntcreatex.in.flags = 0; + status = smb_raw_open(cli->tree, tctx, &io); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "directory open failed"); + fnum = io.ntcreatex.out.file.fnum; + + torture_assert_int_equal(tctx, + io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, + FILE_ATTRIBUTE_DIRECTORY, + "archive bit set"); + + /* + * verify you can turn on archive bit + */ + sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO; + sfinfo.generic.in.file.fnum = fnum; + sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE; + status = smb_raw_setfileinfo(cli->tree, &sfinfo); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "setfileinfo failed"); + + finfo.generic.level = RAW_FILEINFO_ALL_INFO; + finfo.generic.in.file.fnum = fnum; + status = smb_raw_fileinfo(cli->tree, tctx, &finfo); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "fileinfo failed"); + + torture_assert_int_equal(tctx, + finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, + FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE, + "archive bit not set"); + + /* + * and try to turn it back off + */ + sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO; + sfinfo.generic.in.file.fnum = fnum; + sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY; + status = smb_raw_setfileinfo(cli->tree, &sfinfo); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "setfileinfo failed"); + + finfo.generic.level = RAW_FILEINFO_ALL_INFO; + finfo.generic.in.file.fnum = fnum; + status = smb_raw_fileinfo(cli->tree, tctx, &finfo); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "fileinfo failed"); + + torture_assert_int_equal(tctx, + finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, + FILE_ATTRIBUTE_DIRECTORY, + "archive bit set"); + + status = smbcli_close(cli->tree, fnum); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, + ret, done, "close failed"); + +done: + smbcli_close(cli->tree, fnum); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + struct torture_suite *torture_raw_sfileinfo(TALLOC_CTX *mem_ctx) { struct torture_suite *suite = torture_suite_create(mem_ctx, @@ -983,6 +1135,7 @@ struct torture_suite *torture_raw_sfileinfo(TALLOC_CTX *mem_ctx) torture_raw_sfileinfo_eof); torture_suite_add_2smb_test(suite, "END-OF-FILE-ACCESS", torture_raw_sfileinfo_eof_access); + torture_suite_add_1smb_test(suite, "ARCHIVE", torture_raw_sfileinfo_archive); return suite; } -- cgit From 4dc958c7c8cff9044b86e59b9ea8165ee1847aad Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 4 Nov 2009 19:22:53 +0100 Subject: s4:kdc: convert UDP based communication to tdgram_context metze --- source4/kdc/config.mk | 3 +- source4/kdc/kdc.c | 312 ++++++++++++++++++++++---------------------------- 2 files changed, 138 insertions(+), 177 deletions(-) (limited to 'source4') diff --git a/source4/kdc/config.mk b/source4/kdc/config.mk index 7a99857248..a9d01585f0 100644 --- a/source4/kdc/config.mk +++ b/source4/kdc/config.mk @@ -6,7 +6,8 @@ INIT_FUNCTION = server_service_kdc_init SUBSYSTEM = service PRIVATE_DEPENDENCIES = \ - HEIMDAL_KDC HDB_SAMBA4 PAC_GLUE LIBSAMBA-HOSTCONFIG + HEIMDAL_KDC HDB_SAMBA4 PAC_GLUE LIBSAMBA-HOSTCONFIG \ + LIBTSOCKET # End SUBSYSTEM KDC ####################### diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c index 6a9df0bf02..2ee14f551d 100644 --- a/source4/kdc/kdc.c +++ b/source4/kdc/kdc.c @@ -48,13 +48,6 @@ TALLOC_CTX *hdb_samba4_mem_ctx; struct tevent_context *hdb_samba4_ev_ctx; struct loadparm_context *hdb_samba4_lp_ctx; -/* hold all the info needed to send a reply */ -struct kdc_reply { - struct kdc_reply *next, *prev; - struct socket_address *dest; - DATA_BLOB packet; -}; - typedef bool (*kdc_process_fn_t)(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, DATA_BLOB *input, @@ -65,15 +58,11 @@ typedef bool (*kdc_process_fn_t)(struct kdc_server *kdc, /* hold information about one kdc socket */ struct kdc_socket { - struct socket_context *sock; struct kdc_server *kdc; - struct tevent_fd *fde; - - /* a queue of outgoing replies that have been deferred */ - struct kdc_reply *send_queue; - + struct tsocket_address *local_address; kdc_process_fn_t process; }; + /* state of an open tcp connection */ @@ -89,145 +78,6 @@ struct kdc_tcp_connection { kdc_process_fn_t process; }; -/* - handle fd send events on a KDC socket -*/ -static void kdc_send_handler(struct kdc_socket *kdc_socket) -{ - while (kdc_socket->send_queue) { - struct kdc_reply *rep = kdc_socket->send_queue; - NTSTATUS status; - size_t sendlen; - - status = socket_sendto(kdc_socket->sock, &rep->packet, &sendlen, - rep->dest); - if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) { - break; - } - if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_BUFFER_SIZE)) { - /* Replace with a krb err, response to big */ - } - - DLIST_REMOVE(kdc_socket->send_queue, rep); - talloc_free(rep); - } - - if (kdc_socket->send_queue == NULL) { - EVENT_FD_NOT_WRITEABLE(kdc_socket->fde); - } -} - - -/* - handle fd recv events on a KDC socket -*/ -static void kdc_recv_handler(struct kdc_socket *kdc_socket) -{ - NTSTATUS status; - TALLOC_CTX *tmp_ctx = talloc_new(kdc_socket); - DATA_BLOB blob; - struct kdc_reply *rep; - DATA_BLOB reply; - size_t nread, dsize; - struct socket_address *src; - struct socket_address *my_addr; - struct tsocket_address *tsrcaddr; - struct tsocket_address *tmyaddr; - int ret; - - status = socket_pending(kdc_socket->sock, &dsize); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return; - } - - blob = data_blob_talloc(tmp_ctx, NULL, dsize); - if (blob.data == NULL) { - /* hope this is a temporary low memory condition */ - talloc_free(tmp_ctx); - return; - } - - status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread, - tmp_ctx, &src); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return; - } - blob.length = nread; - - DEBUG(10,("Received krb5 UDP packet of length %lu from %s:%u\n", - (long)blob.length, src->addr, (uint16_t)src->port)); - - my_addr = socket_get_my_addr(kdc_socket->sock, tmp_ctx); - if (!my_addr) { - talloc_free(tmp_ctx); - return; - } - - ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, src->sockaddr, - src->sockaddrlen, &tsrcaddr); - if (ret < 0) { - talloc_free(tmp_ctx); - return; - } - - ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, my_addr->sockaddr, - my_addr->sockaddrlen, &tmyaddr); - if (ret < 0) { - talloc_free(tmp_ctx); - return; - } - - /* Call krb5 */ - ret = kdc_socket->process(kdc_socket->kdc, - tmp_ctx, - &blob, - &reply, - tsrcaddr, - tmyaddr, - 1 /* Datagram */); - if (!ret) { - talloc_free(tmp_ctx); - return; - } - - /* queue a pending reply */ - rep = talloc(kdc_socket, struct kdc_reply); - if (rep == NULL) { - talloc_free(tmp_ctx); - return; - } - rep->dest = talloc_steal(rep, src); - rep->packet = reply; - talloc_steal(rep, reply.data); - - if (rep->packet.data == NULL) { - talloc_free(rep); - talloc_free(tmp_ctx); - return; - } - - DLIST_ADD_END(kdc_socket->send_queue, rep, struct kdc_reply *); - EVENT_FD_WRITEABLE(kdc_socket->fde); - talloc_free(tmp_ctx); -} - -/* - handle fd events on a KDC socket -*/ -static void kdc_socket_handler(struct tevent_context *ev, struct tevent_fd *fde, - uint16_t flags, void *private_data) -{ - struct kdc_socket *kdc_socket = talloc_get_type(private_data, struct kdc_socket); - if (flags & EVENT_FD_WRITE) { - kdc_send_handler(kdc_socket); - } - if (flags & EVENT_FD_READ) { - kdc_recv_handler(kdc_socket); - } -} - static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, const char *reason) { stream_terminate_connection(kdcconn->conn, reason); @@ -437,6 +287,105 @@ static const struct stream_server_ops kdc_tcp_stream_ops = { .send_handler = kdc_tcp_send }; +/* hold information about one kdc/kpasswd udp socket */ +struct kdc_udp_socket { + struct kdc_socket *kdc_socket; + struct tdgram_context *dgram; + struct tevent_queue *send_queue; +}; + +struct kdc_udp_call { + struct tsocket_address *src; + DATA_BLOB in; + DATA_BLOB out; +}; + +static void kdc_udp_call_sendto_done(struct tevent_req *subreq); + +static void kdc_udp_call_loop(struct tevent_req *subreq) +{ + struct kdc_udp_socket *sock = tevent_req_callback_data(subreq, + struct kdc_udp_socket); + struct kdc_udp_call *call; + uint8_t *buf; + ssize_t len; + int sys_errno; + int ret; + + call = talloc(sock, struct kdc_udp_call); + if (call == NULL) { + talloc_free(call); + goto done; + } + + len = tdgram_recvfrom_recv(subreq, &sys_errno, + call, &buf, &call->src); + TALLOC_FREE(subreq); + if (len == -1) { + talloc_free(call); + goto done; + } + + call->in.data = buf; + call->in.length = len; + + DEBUG(10,("Received krb5 UDP packet of length %lu from %s\n", + (long)call->in.length, + tsocket_address_string(call->src, call))); + + /* Call krb5 */ + ret = sock->kdc_socket->process(sock->kdc_socket->kdc, + call, + &call->in, + &call->out, + call->src, + sock->kdc_socket->local_address, + 1 /* Datagram */); + if (!ret) { + talloc_free(call); + goto done; + } + + subreq = tdgram_sendto_queue_send(call, + sock->kdc_socket->kdc->task->event_ctx, + sock->dgram, + sock->send_queue, + call->out.data, + call->out.length, + call->src); + if (subreq == NULL) { + talloc_free(call); + goto done; + } + tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call); + +done: + subreq = tdgram_recvfrom_send(sock, + sock->kdc_socket->kdc->task->event_ctx, + sock->dgram); + if (subreq == NULL) { + task_server_terminate(sock->kdc_socket->kdc->task, + "no memory for tdgram_recvfrom_send", + true); + return; + } + tevent_req_set_callback(subreq, kdc_udp_call_loop, sock); +} + +static void kdc_udp_call_sendto_done(struct tevent_req *subreq) +{ + struct kdc_udp_call *call = tevent_req_callback_data(subreq, + struct kdc_udp_call); + ssize_t ret; + int sys_errno; + + ret = tdgram_sendto_queue_recv(subreq, &sys_errno); + + /* We don't care about errors */ + + talloc_free(call); +} + /* start listening on the given address */ @@ -447,38 +396,23 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc, uint16_t port, kdc_process_fn_t process) { - struct kdc_socket *kdc_socket; - struct socket_address *socket_address; + struct kdc_socket *kdc_socket; + struct kdc_udp_socket *kdc_udp_socket; + struct tevent_req *udpsubreq; NTSTATUS status; + int ret; kdc_socket = talloc(kdc, struct kdc_socket); NT_STATUS_HAVE_NO_MEMORY(kdc_socket); - status = socket_create("ip", SOCKET_TYPE_DGRAM, &kdc_socket->sock, 0); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(kdc_socket); - return status; - } - kdc_socket->kdc = kdc; - kdc_socket->send_queue = NULL; kdc_socket->process = process; - talloc_steal(kdc_socket, kdc_socket->sock); - - kdc_socket->fde = event_add_fd(kdc->task->event_ctx, kdc, - socket_get_fd(kdc_socket->sock), EVENT_FD_READ, - kdc_socket_handler, kdc_socket); - - socket_address = socket_address_from_strings(kdc_socket, kdc_socket->sock->backend_name, - address, port); - NT_STATUS_HAVE_NO_MEMORY_AND_FREE(socket_address, kdc_socket); - - status = socket_listen(kdc_socket->sock, socket_address, 0, 0); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to bind to %s:%d UDP for %s - %s\n", - address, port, name, nt_errstr(status))); - talloc_free(kdc_socket); + ret = tsocket_address_inet_from_strings(kdc_socket, "ip", + address, port, + &kdc_socket->local_address); + if (ret != 0) { + status = map_nt_error_from_unix(errno); return status; } @@ -496,6 +430,32 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc, return status; } + kdc_udp_socket = talloc(kdc_socket, struct kdc_udp_socket); + NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket); + + kdc_udp_socket->kdc_socket = kdc_socket; + + ret = tdgram_inet_udp_socket(kdc_socket->local_address, + NULL, + kdc_udp_socket, + &kdc_udp_socket->dgram); + if (ret != 0) { + status = map_nt_error_from_unix(errno); + DEBUG(0,("Failed to bind to %s:%u UDP - %s\n", + address, port, nt_errstr(status))); + return status; + } + + kdc_udp_socket->send_queue = tevent_queue_create(kdc_udp_socket, + "kdc_udp_send_queue"); + NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket->send_queue); + + udpsubreq = tdgram_recvfrom_send(kdc_udp_socket, + kdc->task->event_ctx, + kdc_udp_socket->dgram); + NT_STATUS_HAVE_NO_MEMORY(udpsubreq); + tevent_req_set_callback(udpsubreq, kdc_udp_call_loop, kdc_udp_socket); + return NT_STATUS_OK; } -- cgit From fcbe8f0c80e3848e87d37476a46c7eb553d592c1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 4 Nov 2009 19:22:53 +0100 Subject: s4:kdc: setup the local and remote tsocket_address at accept time metze --- source4/kdc/kdc.c | 93 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 44 deletions(-) (limited to 'source4') diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c index 2ee14f551d..2c07f89f17 100644 --- a/source4/kdc/kdc.c +++ b/source4/kdc/kdc.c @@ -71,11 +71,12 @@ struct kdc_tcp_connection { struct stream_connection *conn; /* the kdc_server the connection belongs to */ - struct kdc_server *kdc; + struct kdc_socket *kdc_socket; - struct packet_context *packet; + struct tsocket_address *local_address; + struct tsocket_address *remote_address; - kdc_process_fn_t process; + struct packet_context *packet; }; static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, const char *reason) @@ -94,49 +95,18 @@ static NTSTATUS kdc_tcp_recv(void *private_data, DATA_BLOB blob) TALLOC_CTX *tmp_ctx = talloc_new(kdcconn); int ret; DATA_BLOB input, reply; - struct socket_address *src_addr; - struct socket_address *my_addr; - struct tsocket_address *tsrcaddr; - struct tsocket_address *tmyaddr; - talloc_steal(tmp_ctx, blob.data); - src_addr = socket_get_peer_addr(kdcconn->conn->socket, tmp_ctx); - if (!src_addr) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - - my_addr = socket_get_my_addr(kdcconn->conn->socket, tmp_ctx); - if (!my_addr) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - - ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, src_addr->sockaddr, - src_addr->sockaddrlen, &tsrcaddr); - if (ret < 0) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - - ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, my_addr->sockaddr, - my_addr->sockaddrlen, &tmyaddr); - if (ret < 0) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - /* Call krb5 */ input = data_blob_const(blob.data + 4, blob.length - 4); - ret = kdcconn->process(kdcconn->kdc, - tmp_ctx, - &input, - &reply, - tsrcaddr, - tmyaddr, - 0 /* Not datagram */); + ret = kdcconn->kdc_socket->process(kdcconn->kdc_socket->kdc, + tmp_ctx, + &input, + &reply, + kdcconn->remote_address, + kdcconn->local_address, + 0 /* Not datagram */); if (!ret) { talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_ERROR; @@ -254,17 +224,52 @@ static void kdc_tcp_accept(struct stream_connection *conn) { struct kdc_socket *kdc_socket = talloc_get_type(conn->private_data, struct kdc_socket); struct kdc_tcp_connection *kdcconn; + struct socket_address *src_addr; + struct socket_address *my_addr; + int ret; kdcconn = talloc_zero(conn, struct kdc_tcp_connection); if (!kdcconn) { stream_terminate_connection(conn, "kdc_tcp_accept: out of memory"); return; } - kdcconn->conn = conn; - kdcconn->kdc = kdc_socket->kdc; - kdcconn->process = kdc_socket->process; + kdcconn->conn = conn; + kdcconn->kdc_socket = kdc_socket; conn->private_data = kdcconn; + src_addr = socket_get_peer_addr(kdcconn->conn->socket, kdcconn); + if (!src_addr) { + kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); + return; + } + + my_addr = socket_get_my_addr(kdcconn->conn->socket, kdcconn); + if (!my_addr) { + kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); + return; + } + + ret = tsocket_address_bsd_from_sockaddr(kdcconn, + src_addr->sockaddr, + src_addr->sockaddrlen, + &kdcconn->remote_address); + if (ret < 0) { + kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); + return; + } + + ret = tsocket_address_bsd_from_sockaddr(kdcconn, + my_addr->sockaddr, + my_addr->sockaddrlen, + &kdcconn->local_address); + if (ret < 0) { + kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); + return; + } + + TALLOC_FREE(src_addr); + TALLOC_FREE(my_addr); + kdcconn->packet = packet_init(kdcconn); if (kdcconn->packet == NULL) { kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); -- cgit From 882768c8785995acccbdf562be99a68fc0dde33b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 13:47:46 +1100 Subject: s4-dsdb: give us an invocationID when in standalone mode To allow us to use the repl_meta_data module in standalone mode (and thus not have two module stacks to test), we need a invocationID stored somewhere when standalone. This creates a random one, and stores it in @SAMBA_DSDB. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/samba_dsdb.c | 80 ++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c index ee7e42ef9b..bfa2599afe 100644 --- a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c +++ b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c @@ -38,6 +38,7 @@ #include "dsdb/samdb/ldb_modules/util.h" #include "dsdb/samdb/samdb.h" +#include "librpc/ndr/libndr.h" static int read_at_rootdse_record(struct ldb_context *ldb, struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_message **msg) @@ -135,6 +136,55 @@ static int prepare_modules_line(struct ldb_context *ldb, return ret; } + + +/* + initialise the invocationID for a standalone server + */ +static int initialise_invocation_id(struct ldb_module *module, struct GUID *guid) +{ + struct ldb_message *msg; + struct ldb_context *ldb = ldb_module_get_ctx(module); + int ret; + + *guid = GUID_random(); + + msg = ldb_msg_new(module); + if (msg == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + msg->dn = ldb_dn_new(msg, ldb, "@SAMBA_DSDB"); + if (!msg->dn) { + ldb_module_oom(module); + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = dsdb_msg_add_guid(msg, guid, "invocationID"); + if (ret != LDB_SUCCESS) { + ldb_module_oom(module); + talloc_free(msg); + return ret; + } + msg->elements[0].flags = LDB_FLAG_MOD_ADD; + + ret = ldb_modify(ldb, msg); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to setup standalone invocationID - %s", + ldb_errstring(ldb)); + talloc_free(msg); + return ret; + } + + DEBUG(1,("Initialised standalone invocationID to %s\n", + GUID_string(msg, guid))); + + talloc_free(msg); + + return LDB_SUCCESS; +} + + static int samba_dsdb_init(struct ldb_module *module) { struct ldb_context *ldb = ldb_module_get_ctx(module); @@ -213,7 +263,7 @@ static int samba_dsdb_init(struct ldb_module *module) static const char *openldap_backend_modules[] = { "entryuuid", "paged_searches", NULL }; - static const char *samba_dsdb_attrs[] = { "backendType", "serverRole", NULL }; + static const char *samba_dsdb_attrs[] = { "backendType", "serverRole", "invocationID", NULL }; const char *backendType, *serverRole; if (!tmp_ctx) { @@ -248,6 +298,34 @@ static int samba_dsdb_init(struct ldb_module *module) return ret; } + if (strcmp(serverRole, "standalone") == 0 || + strcmp(serverRole, "member server") == 0) { + struct GUID *guid; + + guid = talloc(module, struct GUID); + if (!guid) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + *guid = samdb_result_guid(res->msgs[0], "invocationID"); + if (GUID_all_zero(guid)) { + ret = initialise_invocation_id(module, guid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + /* cache the domain_sid in the ldb. See the matching + * code in samdb_ntds_invocation_id() */ + ret = ldb_set_opaque(ldb, "cache.invocation_id", guid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + backend_modules = NULL; if (strcasecmp(backendType, "ldb") == 0) { if (strcasecmp(serverRole, "dc") == 0 || strcasecmp(serverRole, "domain controller") == 0) { -- cgit From dbda2c2db5a3c0c39134fde1ae58ceadf473a87f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 14:45:58 +1100 Subject: s4-provision: added a note about where invocationIDs come from Pair-Programmed-With: Andrew Bartlett --- source4/scripting/python/samba/provision.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 3e4e90a746..d7d0a790ca 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -894,6 +894,8 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, samdb.set_domain_sid(str(domainsid)) if serverrole == "domain controller": samdb.set_invocation_id(invocationid) + # NOTE: the invocationid for standalone and member server + # cases is setup in the sambd_dsdb module init function message("Adding DomainDN: %s" % names.domaindn) -- cgit From 2c88ffb8f1f3691d29a88ab263dde5b07f4f400a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:54:23 +1100 Subject: s4-dsdb: added two new dsdb_get_extended_dn_*() helper functions Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/common/util.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 61d065b85c..774f9a757c 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2734,6 +2734,49 @@ NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid) return GUID_from_ndr_blob(v, guid); } +/* + return a NTTIME from a extended DN structure + */ +NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name) +{ + const struct ldb_val *v; + char *s; + + v = ldb_dn_get_extended_component(dn, component_name); + if (v == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + s = talloc_strndup(dn, (const char *)v->data, v->length); + NT_STATUS_HAVE_NO_MEMORY(s); + + *nttime = strtoull(s, NULL, 0); + + talloc_free(s); + return NT_STATUS_OK; +} + +/* + return a uint32_t from a extended DN structure + */ +NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name) +{ + const struct ldb_val *v; + char *s; + + v = ldb_dn_get_extended_component(dn, component_name); + if (v == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + s = talloc_strndup(dn, (const char *)v->data, v->length); + NT_STATUS_HAVE_NO_MEMORY(s); + + *val = strtoul(s, NULL, 0); + + talloc_free(s); + return NT_STATUS_OK; +} + /* return true if a ldb_val containing a DN in storage form is deleted */ -- cgit From e89a2db4f24ee70c45e0636e9baa8b6212a27cde Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:55:23 +1100 Subject: s4-dsdb: use varargs expression in dsdb_module_search() Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/util.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index 8d9930a81f..acc1c01959 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -164,15 +164,21 @@ int dsdb_module_search(struct ldb_module *module, struct ldb_dn *basedn, enum ldb_scope scope, const char * const *attrs, int dsdb_flags, - const char *expression) + const char *format, ...) _PRINTF_ATTRIBUTE(8, 9) { int ret; struct ldb_request *req; TALLOC_CTX *tmp_ctx; struct ldb_result *res; + va_list ap; + char *expression; tmp_ctx = talloc_new(mem_ctx); + va_start(ap, format); + expression = talloc_vasprintf(tmp_ctx, format, ap); + va_end(ap); + res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { return LDB_ERR_OPERATIONS_ERROR; -- cgit From 9d56f656d4f593289340a876445785cdfefd3d91 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 12:23:42 +1100 Subject: s4-dsdb: added dsdb_get_extended_dn_uint64() --- source4/dsdb/common/util.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 774f9a757c..b0f9ef0f35 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2735,9 +2735,9 @@ NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid) } /* - return a NTTIME from a extended DN structure + return a uint64_t from a extended DN structure */ -NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name) +NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name) { const struct ldb_val *v; char *s; @@ -2749,12 +2749,20 @@ NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const ch s = talloc_strndup(dn, (const char *)v->data, v->length); NT_STATUS_HAVE_NO_MEMORY(s); - *nttime = strtoull(s, NULL, 0); + *val = strtoull(s, NULL, 0); talloc_free(s); return NT_STATUS_OK; } +/* + return a NTTIME from a extended DN structure + */ +NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name) +{ + return dsdb_get_extended_dn_uint64(dn, nttime, component_name); +} + /* return a uint32_t from a extended DN structure */ -- cgit From a070119de34274e6122461d9cc0e9829b5fb6865 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 20:56:41 +1100 Subject: s4-dsdb: added DSDB_MODIFY_RELAX flag to the dsdb_module_*() calls --- source4/dsdb/samdb/ldb_modules/util.c | 7 +++++++ source4/dsdb/samdb/ldb_modules/util.h | 1 + 2 files changed, 8 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index acc1c01959..8503584ea6 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -87,6 +87,13 @@ int dsdb_request_add_controls(struct ldb_module *module, struct ldb_request *req } } + if (dsdb_flags & DSDB_MODIFY_RELAX) { + ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL); + if (ret != LDB_SUCCESS) { + return ret; + } + } + return LDB_SUCCESS; } diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h index 41ed883dc2..cc184eee8f 100644 --- a/source4/dsdb/samdb/ldb_modules/util.h +++ b/source4/dsdb/samdb/ldb_modules/util.h @@ -28,3 +28,4 @@ struct GUID; #define DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT 0x0004 #define DSDB_SEARCH_REVEAL_INTERNALS 0x0008 #define DSDB_SEARCH_SHOW_EXTENDED_DN 0x0010 +#define DSDB_MODIFY_RELAX 0x0020 -- cgit From 47560bfda9932efa6b225a223aba662a4d72e637 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 20:58:00 +1100 Subject: s4-dsdb: don't use a non-constant format string for a printf format --- source4/dsdb/samdb/ldb_modules/util.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index 8503584ea6..b0ccd0341c 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -232,22 +232,15 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx, { struct ldb_result *res; const char *attrs[] = { NULL }; - char *expression; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); int ret; - expression = talloc_asprintf(tmp_ctx, "objectGUID=%s", GUID_string(tmp_ctx, guid)); - if (!expression) { - ldb_module_oom(module); - return LDB_ERR_OPERATIONS_ERROR; - } - ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs, DSDB_SEARCH_SHOW_DELETED | DSDB_SEARCH_SEARCH_ALL_PARTITIONS | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, - expression); + "objectGUID=%s", GUID_string(tmp_ctx, guid)); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -257,8 +250,8 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx, return LDB_ERR_NO_SUCH_OBJECT; } if (res->count != 1) { - ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching %s\n", - expression); + ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n", + GUID_string(tmp_ctx, guid)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } -- cgit From 2a4a159a8443ebaae53f5902a0f5c1f8536a6edd Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 23:32:48 +1100 Subject: s4-repl: lower debug level of a common message --- source4/dsdb/repl/drepl_notify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/repl/drepl_notify.c b/source4/dsdb/repl/drepl_notify.c index e8652dcaf1..fe3b2d2497 100644 --- a/source4/dsdb/repl/drepl_notify.c +++ b/source4/dsdb/repl/drepl_notify.c @@ -404,7 +404,7 @@ WERROR dreplsrv_notify_schedule(struct dreplsrv_service *service, uint32_t next_ W_ERROR_HAVE_NO_MEMORY(new_te); tmp_mem = talloc_new(service); - DEBUG(2,("dreplsrv_notify_schedule(%u) %sscheduled for: %s\n", + DEBUG(4,("dreplsrv_notify_schedule(%u) %sscheduled for: %s\n", next_interval, (service->notify.te?"re":""), nt_time_string(tmp_mem, timeval_to_nttime(&next_time)))); -- cgit From d3708109a141f5d6468a89e35176cb56e7a8d821 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 10:26:06 +1100 Subject: s4-drs: another two unsigned comparison bugs --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3ae165c6da..3d31cc3f49 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -336,7 +336,7 @@ static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMeta return -1; } - return m1->attid - m2->attid; + return m1->attid > m2->attid ? 1 : -1; } static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1, @@ -390,8 +390,10 @@ static int replmd_ldb_message_element_attid_sort(const struct ldb_message_elemen if (!a1 || !a2) { return strcasecmp(e1->name, e2->name); } - - return a1->attributeID_id - a2->attributeID_id; + if (a1->attributeID_id == a2->attributeID_id) { + return 0; + } + return a1->attributeID_id > a2->attributeID_id ? 1 : -1; } static void replmd_ldb_message_sort(struct ldb_message *msg, -- cgit From ec74ffa8f08d85c55ec7fc592101a21340b9a97d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 10:26:21 +1100 Subject: s4-schema: a unsigned comparison bug in the schema code --- source4/dsdb/schema/schema_query.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/schema/schema_query.c b/source4/dsdb/schema/schema_query.c index f563f01272..df17787f38 100644 --- a/source4/dsdb/schema/schema_query.c +++ b/source4/dsdb/schema/schema_query.c @@ -31,7 +31,8 @@ static const char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx, static int uint32_cmp(uint32_t c1, uint32_t c2) { - return c1 - c2; + if (c1 == c2) return 0; + return c1 > c2 ? 1 : -1; } static int strcasecmp_with_ldb_val(const struct ldb_val *target, const char *str) -- cgit From 87f28cc2671cf0211b0f1b286b719c5baf9e8111 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 10:27:17 +1100 Subject: s4-torture: another unsigned comparison bug --- source4/torture/raw/qfileinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/torture/raw/qfileinfo.c b/source4/torture/raw/qfileinfo.c index 85f9f1b093..032df87a4d 100644 --- a/source4/torture/raw/qfileinfo.c +++ b/source4/torture/raw/qfileinfo.c @@ -140,7 +140,7 @@ static int dos_nt_time_cmp(time_t t, NTTIME nt) { time_t t2 = nt_time_to_unix(nt); if (abs(t2 - t) <= 2) return 0; - return t2 - t; + return t2 > t ? 1 : -1; } -- cgit From 60acce584bf75c54c71813c93b6c607ef32c867d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 11:06:23 +1100 Subject: s4-repl: only try to replicate for NCs that we are a master for --- source4/dsdb/repl/drepl_partitions.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/repl/drepl_partitions.c b/source4/dsdb/repl/drepl_partitions.c index 85412a793c..5b8227e7de 100644 --- a/source4/dsdb/repl/drepl_partitions.c +++ b/source4/dsdb/repl/drepl_partitions.c @@ -39,16 +39,15 @@ WERROR dreplsrv_load_partitions(struct dreplsrv_service *s) struct ldb_dn *basedn; struct ldb_result *r; struct ldb_message_element *el; - static const char *attrs[] = { "namingContexts", NULL }; + static const char *attrs[] = { "hasMasterNCs", NULL }; uint32_t i; int ret; - basedn = ldb_dn_new(s, s->samdb, NULL); + basedn = samdb_ntds_settings_dn(s->samdb); W_ERROR_HAVE_NO_MEMORY(basedn); ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs, "(objectClass=*)"); - talloc_free(basedn); if (ret != LDB_SUCCESS) { return WERR_FOOBAR; } else if (r->count != 1) { @@ -56,7 +55,7 @@ WERROR dreplsrv_load_partitions(struct dreplsrv_service *s) return WERR_FOOBAR; } - el = ldb_msg_find_element(r->msgs[0], "namingContexts"); + el = ldb_msg_find_element(r->msgs[0], "hasMasterNCs"); if (!el) { return WERR_FOOBAR; } -- cgit From 92d75a4bfb1d666950f39aba19fcc4d97c2234ad Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 20:57:21 +1100 Subject: s4-kcc: don't crash with a NULL ntds connection list --- source4/dsdb/kcc/kcc_connection.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/kcc/kcc_connection.c b/source4/dsdb/kcc/kcc_connection.c index ee9a05a21e..73198040c4 100644 --- a/source4/dsdb/kcc/kcc_connection.c +++ b/source4/dsdb/kcc/kcc_connection.c @@ -133,7 +133,7 @@ void kccsrv_apply_connections(struct kccsrv_service *s, { int i, j, deleted = 0, added = 0, ret; - for (i = 0; i < ntds_list->count; i++) { + for (i = 0; ntds_list && i < ntds_list->count; i++) { struct kcc_connection *ntds = &ntds_list->servers[i]; for (j = 0; j < dsa_list->count; j++) { struct kcc_connection *dsa = &dsa_list->servers[j]; @@ -152,13 +152,13 @@ void kccsrv_apply_connections(struct kccsrv_service *s, for (i = 0; i < dsa_list->count; i++) { struct kcc_connection *dsa = &dsa_list->servers[i]; - for (j = 0; j < ntds_list->count; j++) { + for (j = 0; ntds_list && j < ntds_list->count; j++) { struct kcc_connection *ntds = &ntds_list->servers[j]; if (GUID_equal(&dsa->dsa_guid, &ntds->dsa_guid)) { break; } } - if (j == ntds_list->count) { + if (ntds_list == NULL || j == ntds_list->count) { ret = kccsrv_add_connection(s, dsa); if (ret == LDB_SUCCESS) { added++; -- cgit From 452fc0d6f44eea0876c3671400d8a8713d00ddce Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 20:58:09 +1100 Subject: s4-repl: give a reason why the prepare commit failed --- source4/dsdb/repl/replicated_objects.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c index 1efbd29d93..abd3ac85da 100644 --- a/source4/dsdb/repl/replicated_objects.c +++ b/source4/dsdb/repl/replicated_objects.c @@ -319,7 +319,8 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb, ret = ldb_transaction_prepare_commit(ldb); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ " Failed to prepare commit of transaction\n")); + DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n", + ldb_errstring(ldb))); return WERR_FOOBAR; } -- cgit From 03a1451bbc663a4dbb102d5e150b92acbe7f9599 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 4 Dec 2009 03:58:59 +0200 Subject: s4-drstest: Don't remove temp LDB so it can be reviewed if necessary This test makes temp directory which is not removed so why not just leave LDB also. Signed-off-by: Andrew Tridgell --- source4/torture/drs/unit/prefixmap_tests.c | 1 - 1 file changed, 1 deletion(-) (limited to 'source4') diff --git a/source4/torture/drs/unit/prefixmap_tests.c b/source4/torture/drs/unit/prefixmap_tests.c index 03f30de106..b2449d285a 100644 --- a/source4/torture/drs/unit/prefixmap_tests.c +++ b/source4/torture/drs/unit/prefixmap_tests.c @@ -663,7 +663,6 @@ static bool torture_drs_unit_ldb_setup(struct torture_context *tctx, struct drsu } DONE: - unlink(ldb_url); talloc_free(mem_ctx); return bret; } -- cgit From d9606d64ddad4e593b02310b392cd11ff4114aa1 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 03:53:13 +0200 Subject: s4-drs: Fix bug - prefixMap is not updated when adding new OIDs. The bug is that prefixMap is updated only memory when adding new Classs/Attribute that has and OID not in prefixMap already. Signed-off-by: Andrew Tridgell --- source4/dsdb/samdb/ldb_modules/schema_data.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c index ed10ae6d69..dfb322225a 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_data.c +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -140,7 +140,6 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) const struct ldb_val *governsID = NULL; const char *oid_attr = NULL; const char *oid = NULL; - uint32_t attid; WERROR status; ldb = ldb_module_get_ctx(module); @@ -184,7 +183,7 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - status = dsdb_schema_pfm_make_attid(schema->prefixmap, oid, &attid); + status = dsdb_schema_pfm_find_oid(schema->prefixmap, oid, NULL); if (W_ERROR_IS_OK(status)) { return ldb_next_request(module, req); } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) { -- cgit From c113be8526fe5a4b67410a557201717ee2a385eb Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Mon, 14 Dec 2009 01:52:18 +0200 Subject: s4-tort: Move Schema tests from ldap.py into separate module Signed-off-by: Andrew Tridgell --- source4/lib/ldb/tests/python/ldap.py | 133 ----------------- source4/lib/ldb/tests/python/ldap_schema.py | 221 ++++++++++++++++++++++++++++ source4/selftest/tests.sh | 1 + 3 files changed, 222 insertions(+), 133 deletions(-) create mode 100755 source4/lib/ldb/tests/python/ldap_schema.py (limited to 'source4') diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py index 54b623a903..426d7b38a0 100755 --- a/source4/lib/ldb/tests/python/ldap.py +++ b/source4/lib/ldb/tests/python/ldap.py @@ -1990,137 +1990,6 @@ class BaseDnTests(unittest.TestCase): self.assertTrue(res[0]["configurationNamingContext"][0] in ncs) self.assertTrue(res[0]["schemaNamingContext"][0] in ncs) -class SchemaTests(unittest.TestCase): - def delete_force(self, ldb, dn): - try: - ldb.delete(dn) - except LdbError, (num, _): - self.assertEquals(num, ERR_NO_SUCH_OBJECT) - - def find_schemadn(self, ldb): - res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"]) - self.assertEquals(len(res), 1) - return res[0]["schemaNamingContext"][0] - - def find_basedn(self, ldb): - res = ldb.search(base="", expression="", scope=SCOPE_BASE, - attrs=["defaultNamingContext"]) - self.assertEquals(len(res), 1) - return res[0]["defaultNamingContext"][0] - - def setUp(self): - self.ldb = ldb - self.schema_dn = self.find_schemadn(ldb) - self.base_dn = self.find_basedn(ldb) - - def test_generated_schema(self): - """Testing we can read the generated schema via LDAP""" - res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE, - attrs=["objectClasses", "attributeTypes", "dITContentRules"]) - self.assertEquals(len(res), 1) - self.assertTrue("dITContentRules" in res[0]) - self.assertTrue("objectClasses" in res[0]) - self.assertTrue("attributeTypes" in res[0]) - - def test_generated_schema_is_operational(self): - """Testing we don't get the generated schema via LDAP by default""" - res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE, - attrs=["*"]) - self.assertEquals(len(res), 1) - self.assertFalse("dITContentRules" in res[0]) - self.assertFalse("objectClasses" in res[0]) - self.assertFalse("attributeTypes" in res[0]) - - - def test_schemaUpdateNow(self): - """Testing schemaUpdateNow""" - attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) - attr_ldap_display_name = attr_name.replace("-", "") - - ldif = """ -dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """ -objectClass: top -objectClass: attributeSchema -adminDescription: """ + attr_name + """ -adminDisplayName: """ + attr_name + """ -cn: """ + attr_name + """ -attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940 -attributeSyntax: 2.5.5.12 -omSyntax: 64 -instanceType: 4 -isSingleValued: TRUE -systemOnly: FALSE -""" - self.ldb.add_ldif(ldif) - - class_name = "test-Class" + time.strftime("%s", time.gmtime()) - class_ldap_display_name = class_name.replace("-", "") - - ldif = """ -dn: CN=%s,%s""" % (class_name, self.schema_dn) + """ -objectClass: top -objectClass: classSchema -adminDescription: """ + class_name + """ -adminDisplayName: """ + class_name + """ -cn: """ + class_name + """ -governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939 -instanceType: 4 -objectClassCategory: 1 -subClassOf: organizationalPerson -systemFlags: 16 -rDNAttID: cn -systemMustContain: cn -systemMustContain: """ + attr_ldap_display_name + """ -systemOnly: FALSE -""" - self.ldb.add_ldif(ldif) - - ldif = """ -dn: -changetype: modify -add: schemaUpdateNow -schemaUpdateNow: 1 -""" - self.ldb.modify_ldif(ldif) - - object_name = "obj" + time.strftime("%s", time.gmtime()) - - ldif = """ -dn: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """ -objectClass: organizationalPerson -objectClass: person -objectClass: """ + class_ldap_display_name + """ -objectClass: top -cn: """ + object_name + """ -instanceType: 4 -objectCategory: CN=%s,%s"""% (class_name, self.schema_dn) + """ -distinguishedName: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """ -name: """ + object_name + """ -""" + attr_ldap_display_name + """: test -""" - self.ldb.add_ldif(ldif) - - # Search for created attribute - res = [] - res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"]) - self.assertEquals(len(res), 1) - self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name) - self.assertTrue("schemaIDGUID" in res[0]) - - # Search for created objectclass - res = [] - res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"]) - self.assertEquals(len(res), 1) - self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name) - self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0]) - self.assertTrue("schemaIDGUID" in res[0]) - - # Search for created object - res = [] - res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["*"]) - self.assertEquals(len(res), 1) - # Delete the object - self.delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn)) if not "://" in host: if os.path.isfile(host): @@ -2141,6 +2010,4 @@ if not runner.run(unittest.makeSuite(BaseDnTests)).wasSuccessful(): rc = 1 if not runner.run(unittest.makeSuite(BasicTests)).wasSuccessful(): rc = 1 -if not runner.run(unittest.makeSuite(SchemaTests)).wasSuccessful(): - rc = 1 sys.exit(rc) diff --git a/source4/lib/ldb/tests/python/ldap_schema.py b/source4/lib/ldb/tests/python/ldap_schema.py new file mode 100755 index 0000000000..f6a6f38ec1 --- /dev/null +++ b/source4/lib/ldb/tests/python/ldap_schema.py @@ -0,0 +1,221 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# This is a port of the original in testprogs/ejs/ldap.js + +import getopt +import optparse +import sys +import time +import random +import base64 +import os + +sys.path.append("bin/python") +sys.path.append("../lib/subunit/python") + +import samba.getopt as options + +from samba.auth import system_session +from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError +from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS +from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM +from ldb import ERR_NOT_ALLOWED_ON_NON_LEAF, ERR_OTHER, ERR_INVALID_DN_SYNTAX +from ldb import ERR_NO_SUCH_ATTRIBUTE, ERR_INSUFFICIENT_ACCESS_RIGHTS +from ldb import ERR_OBJECT_CLASS_VIOLATION, ERR_NOT_ALLOWED_ON_RDN +from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION +from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE +from ldb import Message, MessageElement, Dn +from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE +from samba import Ldb, param, dom_sid_to_rid +from samba import UF_NORMAL_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT +from samba import UF_SERVER_TRUST_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT +from samba import UF_INTERDOMAIN_TRUST_ACCOUNT +from samba import UF_PASSWD_NOTREQD, UF_ACCOUNTDISABLE +from samba import GTYPE_SECURITY_BUILTIN_LOCAL_GROUP +from samba import GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_DOMAIN_LOCAL_GROUP +from samba import GTYPE_SECURITY_UNIVERSAL_GROUP +from samba import GTYPE_DISTRIBUTION_GLOBAL_GROUP +from samba import GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP +from samba import GTYPE_DISTRIBUTION_UNIVERSAL_GROUP +from samba import ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST +from samba import ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP +from samba import ATYPE_SECURITY_UNIVERSAL_GROUP +from samba import ATYPE_DISTRIBUTION_GLOBAL_GROUP +from samba import ATYPE_DISTRIBUTION_LOCAL_GROUP +from samba import ATYPE_DISTRIBUTION_UNIVERSAL_GROUP + +from subunit import SubunitTestRunner +import unittest + +from samba.ndr import ndr_pack, ndr_unpack +from samba.dcerpc import security + +parser = optparse.OptionParser("ldap [options] ") +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) +parser.add_option_group(options.VersionOptions(parser)) +# use command line creds if available +credopts = options.CredentialsOptions(parser) +parser.add_option_group(credopts) +opts, args = parser.parse_args() + +if len(args) < 1: + parser.print_usage() + sys.exit(1) + +host = args[0] + +lp = sambaopts.get_loadparm() +creds = credopts.get_credentials(lp) + + +class SchemaTests(unittest.TestCase): + def delete_force(self, ldb, dn): + try: + ldb.delete(dn) + except LdbError, (num, _): + self.assertEquals(num, ERR_NO_SUCH_OBJECT) + + def find_schemadn(self, ldb): + res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"]) + self.assertEquals(len(res), 1) + return res[0]["schemaNamingContext"][0] + + def find_basedn(self, ldb): + res = ldb.search(base="", expression="", scope=SCOPE_BASE, + attrs=["defaultNamingContext"]) + self.assertEquals(len(res), 1) + return res[0]["defaultNamingContext"][0] + + def setUp(self): + self.ldb = ldb + self.schema_dn = self.find_schemadn(ldb) + self.base_dn = self.find_basedn(ldb) + + def test_generated_schema(self): + """Testing we can read the generated schema via LDAP""" + res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE, + attrs=["objectClasses", "attributeTypes", "dITContentRules"]) + self.assertEquals(len(res), 1) + self.assertTrue("dITContentRules" in res[0]) + self.assertTrue("objectClasses" in res[0]) + self.assertTrue("attributeTypes" in res[0]) + + def test_generated_schema_is_operational(self): + """Testing we don't get the generated schema via LDAP by default""" + res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE, + attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertFalse("dITContentRules" in res[0]) + self.assertFalse("objectClasses" in res[0]) + self.assertFalse("attributeTypes" in res[0]) + + + def test_schemaUpdateNow(self): + """Testing schemaUpdateNow""" + attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + attr_ldap_display_name = attr_name.replace("-", "") + + ldif = """ +dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """ +objectClass: top +objectClass: attributeSchema +adminDescription: """ + attr_name + """ +adminDisplayName: """ + attr_name + """ +cn: """ + attr_name + """ +attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940 +attributeSyntax: 2.5.5.12 +omSyntax: 64 +instanceType: 4 +isSingleValued: TRUE +systemOnly: FALSE +""" + self.ldb.add_ldif(ldif) + + class_name = "test-Class" + time.strftime("%s", time.gmtime()) + class_ldap_display_name = class_name.replace("-", "") + + ldif = """ +dn: CN=%s,%s""" % (class_name, self.schema_dn) + """ +objectClass: top +objectClass: classSchema +adminDescription: """ + class_name + """ +adminDisplayName: """ + class_name + """ +cn: """ + class_name + """ +governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939 +instanceType: 4 +objectClassCategory: 1 +subClassOf: organizationalPerson +systemFlags: 16 +rDNAttID: cn +systemMustContain: cn +systemMustContain: """ + attr_ldap_display_name + """ +systemOnly: FALSE +""" + self.ldb.add_ldif(ldif) + + ldif = """ +dn: +changetype: modify +add: schemaUpdateNow +schemaUpdateNow: 1 +""" + self.ldb.modify_ldif(ldif) + + object_name = "obj" + time.strftime("%s", time.gmtime()) + + ldif = """ +dn: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """ +objectClass: organizationalPerson +objectClass: person +objectClass: """ + class_ldap_display_name + """ +objectClass: top +cn: """ + object_name + """ +instanceType: 4 +objectCategory: CN=%s,%s"""% (class_name, self.schema_dn) + """ +distinguishedName: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """ +name: """ + object_name + """ +""" + attr_ldap_display_name + """: test +""" + self.ldb.add_ldif(ldif) + + # Search for created attribute + res = [] + res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name) + self.assertTrue("schemaIDGUID" in res[0]) + + # Search for created objectclass + res = [] + res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name) + self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0]) + self.assertTrue("schemaIDGUID" in res[0]) + + # Search for created object + res = [] + res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + # Delete the object + self.delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn)) + +if not "://" in host: + if os.path.isfile(host): + host = "tdb://%s" % host + else: + host = "ldap://%s" % host + +ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp) +if not "tdb://" in host: + gc_ldb = Ldb("%s:3268" % host, credentials=creds, + session_info=system_session(), lp=lp) +else: + gc_ldb = None + +runner = SubunitTestRunner() +rc = 0 +if not runner.run(unittest.makeSuite(SchemaTests)).wasSuccessful(): + rc = 1 +sys.exit(rc) diff --git a/source4/selftest/tests.sh b/source4/selftest/tests.sh index 73209efefe..fa487dbd58 100755 --- a/source4/selftest/tests.sh +++ b/source4/selftest/tests.sh @@ -460,6 +460,7 @@ plantest "subunit.python" none $SUBUNITRUN subunit plantest "rpcecho.python" dc:local $SUBUNITRUN samba.tests.dcerpc.rpcecho plantest "winreg.python" dc:local $SUBUNITRUN -U\$USERNAME%\$PASSWORD samba.tests.dcerpc.registry plantest "ldap.python" dc PYTHONPATH="$PYTHONPATH:../lib/subunit/python" $PYTHON $samba4srcdir/lib/ldb/tests/python/ldap.py $CONFIGURATION \$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN +plantest "ldap_schema.python" dc PYTHONPATH="$PYTHONPATH:../lib/subunit/python" $PYTHON $samba4srcdir/lib/ldb/tests/python/ldap_schema.py $CONFIGURATION \$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN plantest "ldap.possibleInferiors.python" dc $PYTHON $samba4srcdir/dsdb/samdb/ldb_modules/tests/possibleinferiors.py $CONFIGURATION ldap://\$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN plantest "ldap.secdesc.python" dc PYTHONPATH="$PYTHONPATH:../lib/subunit/python" $PYTHON $samba4srcdir/lib/ldb/tests/python/sec_descriptor.py $CONFIGURATION \$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN plantest "ldap.acl.python" dc PYTHONPATH="$PYTHONPATH:../lib/subunit/python" $PYTHON $samba4srcdir/lib/ldb/tests/python/acl.py $CONFIGURATION \$SERVER -U\$USERNAME%\$PASSWORD -W \$DOMAIN -- cgit From ee48f583b5f7a7acdf4857d69db49dfa36992f4d Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Thu, 17 Dec 2009 19:27:47 +0200 Subject: s4-tort: Tests for "msDS-IntId" attribute implemented Signed-off-by: Andrew Tridgell --- source4/lib/ldb/tests/python/ldap_schema.py | 283 +++++++++++++++++++++++++++- 1 file changed, 281 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/tests/python/ldap_schema.py b/source4/lib/ldb/tests/python/ldap_schema.py index f6a6f38ec1..f13a4fbc52 100755 --- a/source4/lib/ldb/tests/python/ldap_schema.py +++ b/source4/lib/ldb/tests/python/ldap_schema.py @@ -43,6 +43,7 @@ from samba import ATYPE_SECURITY_UNIVERSAL_GROUP from samba import ATYPE_DISTRIBUTION_GLOBAL_GROUP from samba import ATYPE_DISTRIBUTION_LOCAL_GROUP from samba import ATYPE_DISTRIBUTION_UNIVERSAL_GROUP +from samba import DS_DC_FUNCTION_2003 from subunit import SubunitTestRunner import unittest @@ -110,7 +111,6 @@ class SchemaTests(unittest.TestCase): self.assertFalse("objectClasses" in res[0]) self.assertFalse("attributeTypes" in res[0]) - def test_schemaUpdateNow(self): """Testing schemaUpdateNow""" attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) @@ -201,13 +201,290 @@ name: """ + object_name + """ # Delete the object self.delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn)) + +class SchemaTests_msDS_IntId(unittest.TestCase): + + def setUp(self): + self.ldb = ldb + res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.schema_dn = res[0]["schemaNamingContext"][0] + self.base_dn = res[0]["defaultNamingContext"][0] + self.forest_level = int(res[0]["forestFunctionality"][0]) + + def _ldap_schemaUpdateNow(self): + ldif = """ +dn: +changetype: modify +add: schemaUpdateNow +schemaUpdateNow: 1 +""" + self.ldb.modify_ldif(ldif) + + def _make_obj_names(self, prefix): + class_name = prefix + time.strftime("%s", time.gmtime()) + class_ldap_name = class_name.replace("-", "") + class_dn = "CN=%s,%s" % (class_name, self.schema_dn) + return (class_name, class_ldap_name, class_dn) + + def _is_schema_base_object(self, ldb_msg): + """Test systemFlags for SYSTEM_FLAG_SCHEMA_BASE_OBJECT (16)""" + systemFlags = 0 + if "systemFlags" in ldb_msg: + systemFlags = int(ldb_msg["systemFlags"][0]) + return (systemFlags & 16) != 0 + + def _make_attr_ldif(self, attr_name, attr_dn): + ldif = """ +dn: """ + attr_dn + """ +objectClass: top +objectClass: attributeSchema +adminDescription: """ + attr_name + """ +adminDisplayName: """ + attr_name + """ +cn: """ + attr_name + """ +attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940 +attributeSyntax: 2.5.5.12 +omSyntax: 64 +instanceType: 4 +isSingleValued: TRUE +systemOnly: FALSE +""" + return ldif + + def test_msDS_IntId_on_attr(self): + """Testing msDs-IntId creation for Attributes. + See MS-ADTS - 3.1.1.Attributes + + This test should verify that: + - Creating attribute with 'msDS-IntId' fails with ERR_UNWILLING_TO_PERFORM + - Adding 'msDS-IntId' on existing attribute fails with ERR_CONSTRAINT_VIOLATION + - Creating attribute with 'msDS-IntId' set and FLAG_SCHEMA_BASE_OBJECT flag + set fails with ERR_UNWILLING_TO_PERFORM + - Attributes created with FLAG_SCHEMA_BASE_OBJECT not set have + 'msDS-IntId' attribute added internally + """ + + # 1. Create attribute without systemFlags + # msDS-IntId should be created if forest functional + # level is >= DS_DC_FUNCTION_2003 + # and missing otherwise + (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-1-") + ldif = self._make_attr_ldif(attr_name, attr_dn) + + # try to add msDS-IntId during Attribute creation + ldif_fail = ldif + "msDS-IntId: -1993108831\n" + try: + self.ldb.add_ldif(ldif_fail) + self.fail("Adding attribute with preset msDS-IntId should fail") + except LdbError, (num, _): + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + + # add the new attribute and update schema + self.ldb.add_ldif(ldif) + self._ldap_schemaUpdateNow() + + # Search for created attribute + res = [] + res = self.ldb.search(attr_dn, scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name) + if self.forest_level >= DS_DC_FUNCTION_2003: + if self._is_schema_base_object(res[0]): + self.assertTrue("msDS-IntId" not in res[0]) + else: + self.assertTrue("msDS-IntId" in res[0]) + else: + self.assertTrue("msDS-IntId" not in res[0]) + + msg = Message() + msg.dn = Dn(self.ldb, attr_dn) + msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId") + try: + self.ldb.modify(msg) + self.fail("Modifying msDS-IntId should return error") + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + # 2. Create attribute with systemFlags = FLAG_SCHEMA_BASE_OBJECT + # msDS-IntId should be created if forest functional + # level is >= DS_DC_FUNCTION_2003 + # and missing otherwise + (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-2-") + ldif = self._make_attr_ldif(attr_name, attr_dn) + ldif += "systemFlags: 16\n" + + # try to add msDS-IntId during Attribute creation + ldif_fail = ldif + "msDS-IntId: -1993108831\n" + try: + self.ldb.add_ldif(ldif_fail) + self.fail("Adding attribute with preset msDS-IntId should fail") + except LdbError, (num, _): + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + + # add the new attribute and update schema + self.ldb.add_ldif(ldif) + self._ldap_schemaUpdateNow() + + # Search for created attribute + res = [] + res = self.ldb.search(attr_dn, scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name) + if self.forest_level >= DS_DC_FUNCTION_2003: + if self._is_schema_base_object(res[0]): + self.assertTrue("msDS-IntId" not in res[0]) + else: + self.assertTrue("msDS-IntId" in res[0]) + else: + self.assertTrue("msDS-IntId" not in res[0]) + + msg = Message() + msg.dn = Dn(self.ldb, attr_dn) + msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId") + try: + self.ldb.modify(msg) + self.fail("Modifying msDS-IntId should return error") + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + + def _make_class_ldif(self, class_dn, class_name): + ldif = """ +dn: """ + class_dn + """ +objectClass: top +objectClass: classSchema +adminDescription: """ + class_name + """ +adminDisplayName: """ + class_name + """ +cn: """ + class_name + """ +governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939 +instanceType: 4 +objectClassCategory: 1 +subClassOf: organizationalPerson +rDNAttID: cn +systemMustContain: cn +systemOnly: FALSE +""" + return ldif + + def test_msDS_IntId_on_class(self): + """Testing msDs-IntId creation for Class + Reference: MS-ADTS - 3.1.1.2.4.8 Class classSchema""" + + # 1. Create Class without systemFlags + # msDS-IntId should be created if forest functional + # level is >= DS_DC_FUNCTION_2003 + # and missing otherwise + (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-1-") + ldif = self._make_class_ldif(class_dn, class_name) + + # try to add msDS-IntId during Class creation + ldif_add = ldif + "msDS-IntId: -1993108831\n" + self.ldb.add_ldif(ldif_add) + self._ldap_schemaUpdateNow() + + res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831") + + # add a new Class and update schema + (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-2-") + ldif = self._make_class_ldif(class_dn, class_name) + + self.ldb.add_ldif(ldif) + self._ldap_schemaUpdateNow() + + # Search for created Class + res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertFalse("msDS-IntId" in res[0]) + + msg = Message() + msg.dn = Dn(self.ldb, class_dn) + msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId") + try: + self.ldb.modify(msg) + self.fail("Modifying msDS-IntId should return error") + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + # 2. Create Class with systemFlags = FLAG_SCHEMA_BASE_OBJECT + # msDS-IntId should be created if forest functional + # level is >= DS_DC_FUNCTION_2003 + # and missing otherwise + (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-3-") + ldif = self._make_class_ldif(class_dn, class_name) + ldif += "systemFlags: 16\n" + + # try to add msDS-IntId during Class creation + ldif_add = ldif + "msDS-IntId: -1993108831\n" + self.ldb.add_ldif(ldif_add) + + res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831") + + # add the new Class and update schema + (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-4-") + ldif = self._make_class_ldif(class_dn, class_name) + ldif += "systemFlags: 16\n" + + self.ldb.add_ldif(ldif) + self._ldap_schemaUpdateNow() + + # Search for created Class + res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertFalse("msDS-IntId" in res[0]) + + msg = Message() + msg.dn = Dn(self.ldb, class_dn) + msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId") + try: + self.ldb.modify(msg) + self.fail("Modifying msDS-IntId should return error") + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertFalse("msDS-IntId" in res[0]) + + + def test_verify_msDS_IntId(self): + """Verify msDS-IntId exists only on attributes without FLAG_SCHEMA_BASE_OBJECT flag set""" + count = 0 + res = self.ldb.search(self.schema_dn, scope=SCOPE_ONELEVEL, + expression="objectClass=attributeSchema", + attrs=["systemFlags", "msDS-IntId", "attributeID", "cn"]) + self.assertTrue(len(res) > 1) + for ldb_msg in res: + if self.forest_level >= DS_DC_FUNCTION_2003: + if self._is_schema_base_object(ldb_msg): + self.assertTrue("msDS-IntId" not in ldb_msg) + else: + # don't assert here as there are plenty of + # attributes under w2k8 that are not part of + # Base Schema (SYSTEM_FLAG_SCHEMA_BASE_OBJECT flag not set) + # has not msDS-IntId attribute set + #self.assertTrue("msDS-IntId" in ldb_msg, "msDS-IntId expected on: %s" % ldb_msg.dn) + if "msDS-IntId" not in ldb_msg: + count = count + 1 + print "%3d warning: msDS-IntId expected on: %-30s %s" % (count, ldb_msg["attributeID"], ldb_msg["cn"]) + else: + self.assertTrue("msDS-IntId" not in ldb_msg) + + if not "://" in host: if os.path.isfile(host): host = "tdb://%s" % host else: host = "ldap://%s" % host -ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp) +ldb_options = [] +if host.startswith("ldap://"): + # user 'paged_search' module when connecting remotely + ldb_options = ["modules:paged_searches"] + +ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp, options=ldb_options) if not "tdb://" in host: gc_ldb = Ldb("%s:3268" % host, credentials=creds, session_info=system_session(), lp=lp) @@ -218,4 +495,6 @@ runner = SubunitTestRunner() rc = 0 if not runner.run(unittest.makeSuite(SchemaTests)).wasSuccessful(): rc = 1 +if not runner.run(unittest.makeSuite(SchemaTests_msDS_IntId)).wasSuccessful(): + rc = 1 sys.exit(rc) -- cgit From 14bac3a3e6a9308d9088559cf8f898b6ac4b4d68 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 03:58:29 +0200 Subject: Revert "s4-drs: cope with bogus empty attributes from w2k8-r2" This reverts commit 1287c1d115fb7e8f3954bc05ff65007968403a9c. Next patch should fix the "not recognized ATTIDs" problem Signed-off-by: Andrew Tridgell --- source4/dsdb/repl/replicated_objects.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c index abd3ac85da..c72b107b75 100644 --- a/source4/dsdb/repl/replicated_objects.c +++ b/source4/dsdb/repl/replicated_objects.c @@ -128,15 +128,6 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb, } status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, a, msg->elements, e); - if (!NT_STATUS_IS_OK(status) && a->value_ctr.num_values == 0) { - /* w2k8-r2 occasionally sends bogus empty - attributes with rubbish attribute IDs. The - only think we can do is discard these */ - DEBUG(0,(__location__ ": Discarding bogus empty DsReplicaAttribute with attid 0x%x\n", - a->attid)); - ZERO_STRUCTP(e); - continue; - } W_ERROR_NOT_OK_RETURN(status); m->attid = a->attid; @@ -157,14 +148,6 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb, } } - /* delete any empty elements */ - for (i=0; i < msg->num_elements; i++) { - if (msg->elements[i].name == NULL) { - ldb_msg_remove_element(msg, &msg->elements[i]); - i--; - } - } - if (rdn_m) { struct ldb_message_element *el; el = ldb_msg_find_element(msg, rdn_attr->lDAPDisplayName); -- cgit From 4e8ad284f5813413fdec8426f11e24570d22549b Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 04:08:52 +0200 Subject: s4-schema: Set ATTID in schema cache from "msDS-IntId" According to http://msdn.microsoft.com/en-us/library/cc223224%28PROT.13%29.aspx some Attributes OIDs may not use prefixMap. Setting ATTID in Schema Cache here should work, although this code snippet should be moved in separate function. Signed-off-by: Andrew Tridgell --- source4/dsdb/schema/schema_init.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index 4af36838cd..b8cbedcb7d 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -558,14 +558,19 @@ WERROR dsdb_attribute_from_ldb(struct ldb_context *ldb, /* set an invalid value */ attr->attributeID_id = 0xFFFFFFFF; } else { - status = dsdb_schema_pfm_make_attid(schema->prefixmap, - attr->attributeID_oid, - &attr->attributeID_id); - if (!W_ERROR_IS_OK(status)) { - DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n", - __location__, attr->lDAPDisplayName, attr->attributeID_oid, - win_errstr(status))); - return status; + /* check if msDS-IntId element is set */ + attr->attributeID_id = samdb_result_uint(msg, "msDS-IntId", 0xFFFFFFFF); + if (attr->attributeID_id == 0xFFFFFFFF) { + /* msDS-IntId is not set, make */ + status = dsdb_schema_pfm_make_attid(schema->prefixmap, + attr->attributeID_oid, + &attr->attributeID_id); + if (!W_ERROR_IS_OK(status)) { + DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n", + __location__, attr->lDAPDisplayName, attr->attributeID_oid, + win_errstr(status))); + return status; + } } } GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID); -- cgit From a409c0f0372e5a1d81b4acda5c0fc24ccbe68a7e Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Thu, 17 Dec 2009 23:26:47 +0200 Subject: s4-schema: Constraints on msDS-IntId attribute This attribute can not be modified on existing schema object. msDS-IntId is not allowed during attribute creation also. Signed-off-by: Andrew Tridgell --- source4/dsdb/samdb/ldb_modules/schema_data.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c index dfb322225a..cc609581e4 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_data.c +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -169,6 +169,11 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID"); if (attributeID) { + /* Sanity check for not allowed attributes */ + if (ldb_msg_find_ldb_val(req->op.add.message, "msDS-IntId")) { + return LDB_ERR_UNWILLING_TO_PERFORM; + } + oid_attr = "attributeID"; oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length); } else if (governsID) { @@ -204,6 +209,27 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } +static int schema_data_modify(struct ldb_module *module, struct ldb_request *req) +{ + /* special objects should always go through */ + if (ldb_dn_is_special(req->op.mod.message->dn)) { + return ldb_next_request(module, req); + } + + /* replicated update should always go through */ + if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) { + return ldb_next_request(module, req); + } + + /* msDS-IntId is not allowed to be modified */ + if (ldb_msg_find_ldb_val(req->op.mod.message, "msDS-IntId")) { + return LDB_ERR_CONSTRAINT_VIOLATION; + } + + /* go on with the call chain */ + return ldb_next_request(module, req); +} + static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg, const struct dsdb_schema *schema) { @@ -459,5 +485,6 @@ _PUBLIC_ const struct ldb_module_ops ldb_schema_data_module_ops = { .name = "schema_data", .init_context = schema_data_init, .add = schema_data_add, + .modify = schema_data_modify, .search = schema_data_search }; -- cgit From 516316b107e309a32362b7de9b010b73545480e0 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 03:46:39 +0200 Subject: s4-schema: Implement msDS-IntId attribute generation Signed-off-by: Andrew Tridgell --- source4/dsdb/samdb/ldb_modules/schema_data.c | 147 ++++++++++++++++++++++++--- 1 file changed, 133 insertions(+), 14 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c index cc609581e4..2e99113953 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_data.c +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -92,6 +92,37 @@ struct schema_data_search_data { const struct dsdb_schema *schema; }; +/* context to be used during async operations */ +struct schema_data_context { + struct ldb_module *module; + struct ldb_request *req; + + const struct dsdb_schema *schema; +}; + +/* Create new context using + * ldb_request as memory context */ +static int _schema_data_context_new(struct ldb_module *module, + struct ldb_request *req, + struct schema_data_context **pac) +{ + struct schema_data_context *ac; + struct ldb_context *ldb; + + ldb = ldb_module_get_ctx(module); + + *pac = ac = talloc_zero(req, struct schema_data_context); + if (ac == NULL) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->module = module; + ac->req = req; + ac->schema = dsdb_get_schema(ldb); + + return LDB_SUCCESS; +} + static int schema_data_init(struct ldb_module *module) { struct ldb_context *ldb; @@ -132,6 +163,57 @@ static int schema_data_init(struct ldb_module *module) return LDB_SUCCESS; } + +/* Generate new value for msDs-IntId + * Value should be in 0x80000000..0xBFFFFFFF range + * Generated value is added ldb_msg */ +static int _schema_data_gen_msds_intid(struct schema_data_context *ac, + struct ldb_message *ldb_msg) +{ + uint32_t id; + + /* generate random num in 0x80000000..0xBFFFFFFF */ + id = generate_random() % 0X3FFFFFFF; + id += 0x80000000; + + /* make sure id is unique and adjust if not */ + while (dsdb_attribute_by_attributeID_id(ac->schema, id)) { + id++; + if (id > 0xBFFFFFFF) { + id = 0x80000001; + } + } + + /* add generated msDS-IntId value to ldb_msg */ + return ldb_msg_add_fmt(ldb_msg, "msDS-IntId", "%d", id); +} + +static int _schema_data_add_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct schema_data_context *ac; + + ac = talloc_get_type(req->context, struct schema_data_context); + + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + + if (ares->type != LDB_REPLY_DONE) { + talloc_free(ares); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); +} + static int schema_data_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; @@ -187,23 +269,60 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } - + status = dsdb_schema_pfm_find_oid(schema->prefixmap, oid, NULL); - if (W_ERROR_IS_OK(status)) { - return ldb_next_request(module, req); - } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) { - ldb_debug_set(ldb, LDB_DEBUG_ERROR, - "schema_data_add: failed to map %s[%s]: %s\n", - oid_attr, oid, win_errstr(status)); - return LDB_ERR_UNWILLING_TO_PERFORM; + if (!W_ERROR_IS_OK(status)) { + /* check for internal errors */ + if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "schema_data_add: failed to map %s[%s]: %s\n", + oid_attr, oid, win_errstr(status)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + /* Update prefixMap and save it */ + status = dsdb_create_prefix_mapping(ldb, schema, oid); + if (!W_ERROR_IS_OK(status)) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n", + oid_attr, oid, win_errstr(status)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } } - status = dsdb_create_prefix_mapping(ldb, schema, oid); - if (!W_ERROR_IS_OK(status)) { - ldb_debug_set(ldb, LDB_DEBUG_ERROR, - "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n", - oid_attr, oid, win_errstr(status)); - return LDB_ERR_UNWILLING_TO_PERFORM; + /* generate and add msDS-IntId attr value */ + if (attributeID + && (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2003) + && !(ldb_msg_find_attr_as_uint(req->op.add.message, "systemFlags", 0) & SYSTEM_FLAG_SCHEMA_BASE_OBJECT)) { + struct ldb_message *msg; + struct schema_data_context *ac; + struct ldb_request *add_req; + + if (_schema_data_context_new(module, req, &ac) != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* we have to copy the message as the caller might have it as a const */ + msg = ldb_msg_copy_shallow(ac, req->op.add.message); + if (msg == NULL) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* generate unique value for msDS-IntId attr value */ + if (_schema_data_gen_msds_intid(ac, msg) != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "_schema_data_gen_msds_intid() failed to generate msDS-IntId value\n"); + return LDB_ERR_OPERATIONS_ERROR; + } + + ldb_build_add_req(&add_req, ldb, ac, + msg, + req->controls, + ac, _schema_data_add_callback, + req); + + return ldb_next_request(module, add_req); } return ldb_next_request(module, req); -- cgit From 11e2c5777dc1bd8af1f696e04d0712fe43e7a21a Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 18:11:48 +0200 Subject: s4-dsdb-util: Utility function to process ldb_request in transaction This function is to be used later for manually crafted ldb_requests from within dsdb layer Signed-off-by: Andrew Tridgell --- source4/dsdb/common/util.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index b0f9ef0f35..4f7ddde14c 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -996,6 +996,32 @@ int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_m return ldb_modify(sam_ldb, msg); } +/* + * Handle ldb_request in transaction + */ +static int dsdb_autotransaction_request(struct ldb_context *sam_ldb, + struct ldb_request *req) +{ + int ret; + + ret = ldb_transaction_start(sam_ldb); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_request(sam_ldb, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret == LDB_SUCCESS) { + return ldb_transaction_commit(sam_ldb); + } + ldb_transaction_cancel(sam_ldb); + + return ret; +} + /* return a default security descriptor */ -- cgit From 7685bbbc4ea2ffc522a1582a561477dad2c862b2 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 18:14:38 +0200 Subject: s4-dsdb-util: Execute ldb_request using LDB_CONTROL_AS_SYSTEM This function is intended to be used when data needs to be modified skipping access checks. Signed-off-by: Andrew Tridgell --- source4/dsdb/common/util.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 4f7ddde14c..561edff94c 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -1022,6 +1022,55 @@ static int dsdb_autotransaction_request(struct ldb_context *sam_ldb, return ret; } +/* + * replace elements in a record using LDB_CONTROL_AS_SYSTEM + * used to skip access checks on operations + * that are performed by the system + */ +int samdb_replace_as_system(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_message *msg) +{ + int i; + int ldb_ret; + struct ldb_request *req = NULL; + + /* mark all the message elements as LDB_FLAG_MOD_REPLACE */ + for (i=0;inum_elements;i++) { + msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + } + + + ldb_ret = ldb_msg_sanity_check(sam_ldb, msg); + if (ldb_ret != LDB_SUCCESS) { + return ldb_ret; + } + + ldb_ret = ldb_build_mod_req(&req, sam_ldb, mem_ctx, + msg, + NULL, + NULL, + ldb_op_default_callback, + NULL); + + if (ldb_ret != LDB_SUCCESS) { + talloc_free(req); + return ldb_ret; + } + + ldb_ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL); + if (ldb_ret != LDB_SUCCESS) { + talloc_free(req); + return ldb_ret; + } + + /* do request and auto start a transaction */ + ldb_ret = dsdb_autotransaction_request(sam_ldb, req); + + talloc_free(req); + return ldb_ret; +} + /* return a default security descriptor */ -- cgit From 9f6c81874f6e63f30432814e4f443a69c4e04429 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 18:15:49 +0200 Subject: s4-drs: Save prefix map using LDB_CONTROL_AS_SYSTEM control Signed-off-by: Andrew Tridgell --- source4/dsdb/schema/schema_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index b8cbedcb7d..ccdf97cf2d 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -310,7 +310,7 @@ WERROR dsdb_write_prefixes_from_schema_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_co return WERR_NOMEM; } - ldb_ret = samdb_replace( ldb, msg, msg ); + ldb_ret = samdb_replace_as_system(ldb, temp_ctx, msg); talloc_free(temp_ctx); -- cgit From 35b8808b94808f5d689c2b034ff5c21c739c11a4 Mon Sep 17 00:00:00 2001 From: Nadezhda Ivanova Date: Fri, 18 Dec 2009 18:00:15 +0200 Subject: Adapted acl module to skip checks if as_system control is provided. Signed-off-by: Andrew Tridgell --- source4/dsdb/samdb/ldb_modules/acl.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c index b70b8956bb..a3298362f3 100644 --- a/source4/dsdb/samdb/ldb_modules/acl.c +++ b/source4/dsdb/samdb/ldb_modules/acl.c @@ -447,8 +447,10 @@ static int acl_allowedAttributes(struct ldb_module *module, if (ac->allowedAttributesEffective) { struct security_descriptor *sd; struct dom_sid *sid = NULL; + struct ldb_control *as_system = ldb_request_get_control(ac->req, + LDB_CONTROL_AS_SYSTEM_OID); ldb_msg_remove_attr(msg, "allowedAttributesEffective"); - if (ac->user_type == SECURITY_SYSTEM) { + if (ac->user_type == SECURITY_SYSTEM || as_system) { for (i=0; attr_list && attr_list[i]; i++) { ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]); } @@ -559,10 +561,12 @@ static int acl_childClassesEffective(struct ldb_module *module, const struct dsdb_schema *schema = dsdb_get_schema(ldb); const struct dsdb_class *sclass; struct security_descriptor *sd; + struct ldb_control *as_system = ldb_request_get_control(ac->req, + LDB_CONTROL_AS_SYSTEM_OID); struct dom_sid *sid = NULL; int i, j, ret; - if (ac->user_type == SECURITY_SYSTEM) { + if (ac->user_type == SECURITY_SYSTEM || as_system) { return acl_childClasses(module, sd_msg, msg, "allowedChildClassesEffective"); } @@ -635,6 +639,8 @@ static int acl_sDRightsEffective(struct ldb_module *module, struct ldb_message_element *rightsEffective; int ret; struct security_descriptor *sd; + struct ldb_control *as_system = ldb_request_get_control(ac->req, + LDB_CONTROL_AS_SYSTEM_OID); struct dom_sid *sid = NULL; uint32_t flags = 0; @@ -644,7 +650,7 @@ static int acl_sDRightsEffective(struct ldb_module *module, if (ret != LDB_SUCCESS) { return ret; } - if (ac->user_type == SECURITY_SYSTEM) { + if (ac->user_type == SECURITY_SYSTEM || as_system) { flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_SACL | SECINFO_DACL; } else { @@ -699,8 +705,9 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req) const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); - if (what_is_user(module) == SECURITY_SYSTEM) { + if (what_is_user(module) == SECURITY_SYSTEM || as_system) { return ldb_next_request(module, req); } @@ -752,6 +759,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) struct ldb_result *acl_res; struct security_descriptor *sd; struct dom_sid *sid = NULL; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); TALLOC_CTX *tmp_ctx = talloc_new(req); static const char *acl_attrs[] = { "nTSecurityDescriptor", @@ -765,7 +773,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) { DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name)); } - if (what_is_user(module) == SECURITY_SYSTEM) { + if (what_is_user(module) == SECURITY_SYSTEM || as_system) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.mod.message->dn)) { @@ -890,9 +898,10 @@ static int acl_delete(struct ldb_module *module, struct ldb_request *req) int ret; struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.del.dn); struct ldb_context *ldb; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn))); - if (what_is_user(module) == SECURITY_SYSTEM) { + if (what_is_user(module) == SECURITY_SYSTEM || as_system) { return ldb_next_request(module, req); } @@ -934,6 +943,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); TALLOC_CTX *tmp_ctx = talloc_new(req); NTSTATUS status; uint32_t access_granted; @@ -945,7 +955,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) }; DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); - if (what_is_user(module) == SECURITY_SYSTEM) { + if (what_is_user(module) == SECURITY_SYSTEM || as_system) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.rename.olddn)) { -- cgit From 911cefd48be67878dea89f905bc7de1cd3f7c40f Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Sat, 19 Dec 2009 01:48:41 +0200 Subject: s4-tort: Test handling of different ATTID values in prefixMap interface. It turns out ATTID values are separated in ranges. Ref: MS-ADTS, 3.1.1.2.6 ATTRTYP Signed-off-by: Andrew Tridgell --- source4/torture/drs/unit/prefixmap_tests.c | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'source4') diff --git a/source4/torture/drs/unit/prefixmap_tests.c b/source4/torture/drs/unit/prefixmap_tests.c index b2449d285a..4bfdcc0d8b 100644 --- a/source4/torture/drs/unit/prefixmap_tests.c +++ b/source4/torture/drs/unit/prefixmap_tests.c @@ -382,6 +382,48 @@ static bool torture_drs_unit_pfm_oid_from_attid(struct torture_context *tctx, st return true; } +/** + * Tests dsdb_schema_pfm_oid_from_attid() for handling + * correctly different type of attid values. + * See: MS-ADTS, 3.1.1.2.6 ATTRTYP + */ +static bool torture_drs_unit_pfm_oid_from_attid_check_attid(struct torture_context *tctx, + struct drsut_prefixmap_data *priv) +{ + WERROR werr; + const char *oid; + + /* Test with valid prefixMap attid */ + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x00000000, tctx, &oid); + torture_assert_werr_ok(tctx, werr, "Testing prefixMap type attid = 0x0000000"); + + /* Test with attid in msDS-IntId range */ + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x80000000, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing msDS-IntId type attid = 0x80000000"); + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xBFFFFFFF, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing msDS-IntId type attid = 0xBFFFFFFF"); + + /* Test with attid in RESERVED range */ + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xC0000000, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing RESERVED type attid = 0xC0000000"); + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFEFFFF, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing RESERVED type attid = 0xFFFEFFFF"); + + /* Test with attid in INTERNAL range */ + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFF0000, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing INTERNAL type attid = 0xFFFF0000"); + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFFFFFF, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing INTERNAL type attid = 0xFFFFFFFF"); + + return true; +} + /** * Test Schema prefixMap conversions to/from drsuapi prefixMap * representation. @@ -721,6 +763,8 @@ struct torture_tcase * torture_drs_unit_prefixmap(struct torture_suite *suite) torture_tcase_add_simple_test(tc, "make_attid_full_map", (pfn_run)torture_drs_unit_pfm_make_attid_full_map); torture_tcase_add_simple_test(tc, "make_attid_small_map", (pfn_run)torture_drs_unit_pfm_make_attid_small_map); torture_tcase_add_simple_test(tc, "oid_from_attid_full_map", (pfn_run)torture_drs_unit_pfm_oid_from_attid); + torture_tcase_add_simple_test(tc, "oid_from_attid_check_attid", + (pfn_run)torture_drs_unit_pfm_oid_from_attid_check_attid); torture_tcase_add_simple_test(tc, "pfm_to_from_drsuapi", (pfn_run)torture_drs_unit_pfm_to_from_drsuapi); -- cgit From ad35153ef40ade858302dab2877353682604265b Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Sat, 19 Dec 2009 01:49:31 +0200 Subject: s4-drs: Implement constraints on ATTID values in prefixMap Ref: MS-ADTS, 3.1.1.2.6 ATTRTYP Signed-off-by: Andrew Tridgell --- source4/dsdb/schema/prefixmap.h | 11 +++++++++++ source4/dsdb/schema/schema_prefixmap.c | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/schema/prefixmap.h b/source4/dsdb/schema/prefixmap.h index 816ddcfbb3..74acecb4ff 100644 --- a/source4/dsdb/schema/prefixmap.h +++ b/source4/dsdb/schema/prefixmap.h @@ -22,6 +22,17 @@ #ifndef _DSDB_PREFIXMAP_H #define _DSDB_PREFIXMAP_H +/** + * ATTRTYP ranges + * Ref: MS-ADTS, 3.1.1.2.6 ATTRTYP + */ +enum dsdb_attid_type { + dsdb_attid_type_pfm = 1, /* attid in [0x00000000..0x7FFFFFFF] */ + dsdb_attid_type_intid = 2, /* attid in [0x80000000..0xBFFFFFFF] */ + dsdb_attid_type_reserved = 3, /* attid in [0xC0000000..0xFFFEFFFF] */ + dsdb_attid_type_internal = 4, /* attid in [0xFFFF0000..0xFFFFFFFF] */ +}; + /** * oid-prefix in prefixmap */ diff --git a/source4/dsdb/schema/schema_prefixmap.c b/source4/dsdb/schema/schema_prefixmap.c index 969b357a39..89d33779e4 100644 --- a/source4/dsdb/schema/schema_prefixmap.c +++ b/source4/dsdb/schema/schema_prefixmap.c @@ -26,6 +26,25 @@ #include "../lib/util/asn1.h" +/** + * Determine range type for supplied ATTID + */ +enum dsdb_attid_type dsdb_pfm_get_attid_type(uint32_t attid) +{ + if (attid <= 0x7FFFFFFF) { + return dsdb_attid_type_pfm; + } + else if (attid <= 0xBFFFFFFF) { + return dsdb_attid_type_intid; + } + else if (attid <= 0xFFFEFFFF) { + return dsdb_attid_type_reserved; + } + else { + return dsdb_attid_type_internal; + } +} + /** * Allocates schema_prefixMap object in supplied memory context */ @@ -303,6 +322,11 @@ WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_ struct dsdb_schema_prefixmap_oid *pfm_entry; WERROR werr = WERR_OK; + /* sanity check for attid requested */ + if (dsdb_pfm_get_attid_type(attid) != dsdb_attid_type_pfm) { + return WERR_INVALID_PARAMETER; + } + /* crack attid value */ hi_word = attid >> 16; lo_word = attid & 0xFFFF; -- cgit From ec7dc6a619d7fca83a49065c45fdbc0fa93249a0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 23:19:08 +1100 Subject: s4-torture: update uuid_compare test for new behaviour --- source4/torture/ndr/ndr.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/torture/ndr/ndr.c b/source4/torture/ndr/ndr.c index 8602003017..471c398b77 100644 --- a/source4/torture/ndr/ndr.c +++ b/source4/torture/ndr/ndr.c @@ -233,12 +233,21 @@ static bool test_compare_uuid(struct torture_context *tctx) "GUID diff invalid"); g1.time_low = 10; - torture_assert_int_equal(tctx, 10, GUID_compare(&g1, &g2), + torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2), "GUID diff invalid"); g1.time_low = 0; g1.clock_seq[1] = 20; - torture_assert_int_equal(tctx, 20, GUID_compare(&g1, &g2), + torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2), + "GUID diff invalid"); + + g1.time_low = ~0; + torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2), + "GUID diff invalid"); + + g1.time_low = 0; + g2.time_low = ~0; + torture_assert_int_equal(tctx, -1, GUID_compare(&g1, &g2), "GUID diff invalid"); return true; } -- cgit From 0c362597c0f933b3612bb17328c0a13b73d72e43 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 23:36:23 +1100 Subject: s4-schema: fixed the sorting of schema attributes another case of unsigned int subtracting breaking sorts. This one surfaced now as attributeID_id now can be larger than 2^31 --- source4/dsdb/schema/schema_set.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c index e65e372623..f59fc32696 100644 --- a/source4/dsdb/schema/schema_set.c +++ b/source4/dsdb/schema/schema_set.c @@ -180,13 +180,19 @@ op_error: return LDB_ERR_OPERATIONS_ERROR; } +static int uint32_cmp(uint32_t c1, uint32_t c2) +{ + if (c1 == c2) return 0; + return c1 > c2 ? 1 : -1; +} + static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2) { return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName); } static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2) { - return (*c1)->governsID_id - (*c2)->governsID_id; + return uint32_cmp((*c1)->governsID_id, (*c2)->governsID_id); } static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2) { @@ -203,7 +209,7 @@ static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1, } static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2) { - return (*a1)->attributeID_id - (*a2)->attributeID_id; + return uint32_cmp((*a1)->attributeID_id, (*a2)->attributeID_id); } static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2) { @@ -211,7 +217,7 @@ static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, } static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2) { - return (*a1)->linkID - (*a2)->linkID; + return uint32_cmp((*a1)->linkID, (*a2)->linkID); } /* -- cgit From c8e62797eb2b78427c9ecb193c878c646145c32a Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 20 Dec 2009 17:49:48 +0100 Subject: Fix initialisation of TypeObject samba.param.LoadparmService. Found by Ricardo Jorge . --- source4/param/pyparam.c | 3 +++ source4/param/tests/bindings.py | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/param/pyparam.c b/source4/param/pyparam.c index eb2da11bb0..b4255002d2 100644 --- a/source4/param/pyparam.c +++ b/source4/param/pyparam.c @@ -374,6 +374,9 @@ void initparam(void) if (PyType_Ready(&PyLoadparmContext) < 0) return; + if (PyType_Ready(&PyLoadparmService) < 0) + return; + m = Py_InitModule3("param", pyparam_methods, "Parsing and writing Samba configuration files."); if (m == NULL) return; diff --git a/source4/param/tests/bindings.py b/source4/param/tests/bindings.py index 41a67f93fc..1915e79223 100644 --- a/source4/param/tests/bindings.py +++ b/source4/param/tests/bindings.py @@ -2,17 +2,17 @@ # Unix SMB/CIFS implementation. # Copyright (C) Jelmer Vernooij 2007 -# +# # 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 3 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, see . # @@ -50,3 +50,7 @@ class LoadParmTestCase(unittest.TestCase): file = param.LoadParm() file.load_default() + def test_section_nonexistant(self): + samba_lp = param.LoadParm() + samba_lp.load_default() + self.assertRaises(KeyError, samba_lp.__getitem__, "nonexistant") -- cgit From 1d9a243d68539438441a488d09c1200bf22c7462 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 20 Dec 2009 18:05:38 +0100 Subject: ldb_wrap: Fix compilation when using system ldb. --- source4/lib/ldb_wrap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/lib/ldb_wrap.c b/source4/lib/ldb_wrap.c index 134c2271fd..d5178467b1 100644 --- a/source4/lib/ldb_wrap.c +++ b/source4/lib/ldb_wrap.c @@ -34,7 +34,7 @@ #include "ldb_wrap.h" #include "dsdb/samdb/samdb.h" #include "param/param.h" -#include "dlinklist.h" +#include "../lib/util/dlinklist.h" #include "../tdb/include/tdb.h" /* -- cgit From 5b9e98a3826f294a9a9451adacdf77839d30244d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 20 Dec 2009 18:31:27 +0100 Subject: provision/pyldb: Avoid linking in static python ldb module. --- source4/lib/ldb/pyldb.c | 4 +++- source4/lib/ldb/pyldb.h | 1 - source4/param/config.mk | 2 +- source4/param/provision.c | 31 ++++++++++++++++++++++++++++--- 4 files changed, 32 insertions(+), 6 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/pyldb.c b/source4/lib/ldb/pyldb.c index 0ba69e1c48..a19768d41b 100644 --- a/source4/lib/ldb/pyldb.c +++ b/source4/lib/ldb/pyldb.c @@ -61,6 +61,8 @@ PyAPI_DATA(PyTypeObject) PyLdb; PyAPI_DATA(PyTypeObject) PyLdbMessageElement; PyAPI_DATA(PyTypeObject) PyLdbTree; +static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx); + static PyObject *PyObject_FromLdbValue(struct ldb_context *ldb_ctx, struct ldb_message_element *el, struct ldb_val *val) @@ -1357,7 +1359,7 @@ static PySequenceMethods py_ldb_seq = { .sq_contains = (objobjproc)py_ldb_contains, }; -PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx) +static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx) { PyLdbObject *ret; diff --git a/source4/lib/ldb/pyldb.h b/source4/lib/ldb/pyldb.h index a0954158bd..289159c5b3 100644 --- a/source4/lib/ldb/pyldb.h +++ b/source4/lib/ldb/pyldb.h @@ -35,7 +35,6 @@ typedef struct { TALLOC_CTX *mem_ctx; } PyLdbObject; -PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx); #define PyLdb_AsLdbContext(pyobj) ((PyLdbObject *)pyobj)->ldb_ctx #define PyLdb_Check(ob) PyObject_TypeCheck(ob, &PyLdb) diff --git a/source4/param/config.mk b/source4/param/config.mk index 6e5290b64d..02bbdd5677 100644 --- a/source4/param/config.mk +++ b/source4/param/config.mk @@ -13,7 +13,7 @@ PUBLIC_HEADERS += param/param.h PC_FILES += $(paramsrcdir)/samba-hostconfig.pc [SUBSYSTEM::PROVISION] -PRIVATE_DEPENDENCIES = LIBPYTHON pyldb pyparam_util +PRIVATE_DEPENDENCIES = LIBPYTHON pyparam_util PROVISION_OBJ_FILES = $(paramsrcdir)/provision.o $(param_OBJ_FILES) diff --git a/source4/param/provision.c b/source4/param/provision.c index 8c6e1c0f68..7bd10ca522 100644 --- a/source4/param/provision.c +++ b/source4/param/provision.c @@ -52,6 +52,34 @@ static PyObject *schema_module(void) return PyImport_Import(name); } +static PyObject *ldb_module(void) +{ + PyObject *name = PyString_FromString("ldb"); + if (name == NULL) + return NULL; + return PyImport_Import(name); +} + +static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx) +{ + PyLdbObject *ret; + PyObject *ldb_mod = ldb_module(); + PyTypeObject *ldb_ctx_type; + if (ldb_mod == NULL) + return NULL; + + ldb_ctx_type = PyObject_GetAttrString(ldb_mod, "Ldb"); + + ret = (PyLdbObject *)ldb_ctx_type->tp_alloc(ldb_ctx_type, 0); + if (ret == NULL) { + PyErr_NoMemory(); + return NULL; + } + ret->mem_ctx = talloc_new(NULL); + ret->ldb_ctx = talloc_reference(ret->mem_ctx, ldb_ctx); + return (PyObject *)ret; +} + NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct provision_settings *settings, struct provision_result *result) @@ -167,8 +195,6 @@ NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, return NT_STATUS_OK; } -extern void initldb(void); - static PyObject *py_dom_sid_FromSid(struct dom_sid *sid) { PyObject *mod_security, *dom_sid_Type; @@ -220,7 +246,6 @@ NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context py_load_samba_modules(); Py_Initialize(); py_update_path("bin"); /* FIXME: Can't assume this is always the case */ - initldb(); provision_mod = provision_module(); if (provision_mod == NULL) { -- cgit From 2a9c22798d829d80f5735899e9a178c3fdfdbd1f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 22 Dec 2009 01:24:58 +0100 Subject: param: Fix build on systems without ldb installed. --- source4/param/config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/param/config.mk b/source4/param/config.mk index 02bbdd5677..a5bcea691b 100644 --- a/source4/param/config.mk +++ b/source4/param/config.mk @@ -13,7 +13,7 @@ PUBLIC_HEADERS += param/param.h PC_FILES += $(paramsrcdir)/samba-hostconfig.pc [SUBSYSTEM::PROVISION] -PRIVATE_DEPENDENCIES = LIBPYTHON pyparam_util +PRIVATE_DEPENDENCIES = LIBPYTHON pyparam_util LIBLDB PROVISION_OBJ_FILES = $(paramsrcdir)/provision.o $(param_OBJ_FILES) -- cgit From fd0c3a226486eae63166a05d3746626f9f833693 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Mon, 21 Dec 2009 14:38:45 -0800 Subject: s4 torture: Do a better job of closing open files in RAW-OPLOCK. --- source4/torture/raw/oplock.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index 78987e3121..6a0de2e200 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -2178,9 +2178,8 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_ CHECK_STATUS(tctx, status, NT_STATUS_OK); CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3); - smbcli_close(cli1->tree, fnum); - done: + smbcli_close(cli1->tree, fnum); smb_raw_exit(cli1->session); smb_raw_exit(cli2->session); smbcli_deltree(cli1->tree, BASEDIR); @@ -2284,9 +2283,8 @@ bool test_trans2rename(struct torture_context *tctx, struct smbcli_state *cli1, CHECK_STATUS(tctx, status, NT_STATUS_OK); CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3); - smbcli_close(cli1->tree, fnum); - done: + smbcli_close(cli1->tree, fnum); smb_raw_exit(cli1->session); smb_raw_exit(cli2->session); smbcli_deltree(cli1->tree, BASEDIR); @@ -2542,9 +2540,10 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_ CHECK_STATUS(tctx, status, NT_STATUS_OK); CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3); - smbcli_close(cli1->tree, fnum); done: + smbcli_close(cli1->tree, fnum); + smbcli_close(cli2->tree, fnum2); smb_raw_exit(cli1->session); smb_raw_exit(cli2->session); smbcli_deltree(cli1->tree, BASEDIR); -- cgit From c33988c0404ec57fc595000f6dbb477b04e9346d Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Mon, 21 Dec 2009 14:48:43 -0800 Subject: s4 torture: Be more permissive with share modes for oplock testing Share modes are tested elsewhere, and there is currently an outstanding issue about share mode contention for nt-passthrough levels: http://lists.samba.org/archive/cifs-protocol/2009-December/001227.html --- source4/torture/raw/oplock.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index 6a0de2e200..f323c74679 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -2117,7 +2117,8 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; - io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; @@ -2222,7 +2223,8 @@ bool test_trans2rename(struct torture_context *tctx, struct smbcli_state *cli1, io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; - io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; -- cgit From 43a8b49f836fd22b85c0d028873a234319334076 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Tue, 1 Dec 2009 17:40:30 -0800 Subject: s4 torture: Update raw oplock to use win7 as the baseline for rename oplock break behavior --- source4/torture/raw/oplock.c | 79 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 13 deletions(-) (limited to 'source4') diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index f323c74679..9264ddf30a 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -2135,7 +2135,8 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_ fnum = io.ntcreatex.out.file.fnum; CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); - torture_comment(tctx, "setpathinfo rename info should not trigger a break nor a violation\n"); + torture_comment(tctx, "setpathinfo rename info should trigger a break " + "to none\n"); ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; sfi.generic.in.file.path = fname1; @@ -2147,7 +2148,22 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_ CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_wait_for_oplock_break(tctx); - CHECK_VAL(break_info.count, 0); + + CHECK_VAL(break_info.failures, 0); + + if (TARGET_IS_WINXP(tctx)) { + /* Win XP breaks to level2. */ + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + } else if (TARGET_IS_W2K3(tctx) || TARGET_IS_W2K8(tctx) || + TARGET_IS_SAMBA3(tctx) || TARGET_IS_SAMBA4(tctx)) { + /* Win2K3/2k8 incorrectly doesn't break at all. */ + CHECK_VAL(break_info.count, 0); + } else { + /* win7/2k8r2 break to none. */ + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE); + } ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; @@ -2157,7 +2173,16 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_ CHECK_STATUS(tctx, status, NT_STATUS_OK); CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2); - torture_comment(tctx, "setfileinfo rename info should not trigger a break nor a violation\n"); + /* Close and re-open file with oplock. */ + smbcli_close(cli1->tree, fnum); + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); + + torture_comment(tctx, "setfileinfo rename info on a client's own fid " + "should not trigger a break nor a violation\n"); + ZERO_STRUCT(break_info); ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; sfi.generic.in.file.fnum = fnum; @@ -2169,7 +2194,13 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_ CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_wait_for_oplock_break(tctx); - CHECK_VAL(break_info.count, 0); + if (TARGET_IS_WINXP(tctx)) { + /* XP incorrectly breaks to level2. */ + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + } else { + CHECK_VAL(break_info.count, 0); + } ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; @@ -2469,7 +2500,6 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_ fnum = io.ntcreatex.out.file.fnum; CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); - torture_comment(tctx, "setpathinfo rename info should not trigger a break nor a violation\n"); ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; sfi.generic.in.file.path = fname1; @@ -2481,7 +2511,21 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_ CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_wait_for_oplock_break(tctx); - CHECK_VAL(break_info.count, 0); + CHECK_VAL(break_info.failures, 0); + + if (TARGET_IS_WINXP(tctx)) { + /* Win XP breaks to level2. */ + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + } else if (TARGET_IS_W2K3(tctx) || TARGET_IS_W2K8(tctx) || + TARGET_IS_SAMBA3(tctx) || TARGET_IS_SAMBA4(tctx)) { + /* Win2K3/2k8 incorrectly doesn't break at all. */ + CHECK_VAL(break_info.count, 0); + } else { + /* win7/2k8r2 break to none. */ + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE); + } ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; @@ -2506,11 +2550,22 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); torture_wait_for_oplock_break(tctx); - CHECK_VAL(break_info.count, 1); - CHECK_VAL(break_info.failures, 0); - CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); - torture_comment(tctx, "setfileinfo rename info should not trigger a break nor a violation\n"); + if (TARGET_IS_WINXP(tctx)) { + /* XP broke to level2, and doesn't break again. */ + CHECK_VAL(break_info.count, 0); + } else if (TARGET_IS_W2K3(tctx) || TARGET_IS_W2K8(tctx) || + TARGET_IS_SAMBA3(tctx) || TARGET_IS_SAMBA4(tctx)) { + /* Win2K3 incorrectly didn't break before so break now. */ + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + } else { + /* win7/2k8r2 broke to none, and doesn't break again. */ + CHECK_VAL(break_info.count, 0); + } + + ZERO_STRUCT(break_info); + ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; sfi.generic.in.file.fnum = fnum; @@ -2522,9 +2577,7 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_ CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_wait_for_oplock_break(tctx); - CHECK_VAL(break_info.count, 1); - CHECK_VAL(break_info.failures, 0); - CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + CHECK_VAL(break_info.count, 0); ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; -- cgit From fd5350de1f6c233b275b463a35eac48f85478337 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Wed, 2 Dec 2009 11:39:50 -0800 Subject: s4 torture: Add RAW-OPLOCK-EXCLUSIVE7 which is similar to BATCH19 --- source4/torture/raw/oplock.c | 171 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) (limited to 'source4') diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index 9264ddf30a..8bf3a2d97f 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -697,6 +697,176 @@ done: return ret; } +/** + * Exclusive version of batch19 + */ +static bool test_raw_oplock_exclusive7(struct torture_context *tctx, + struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname1 = BASEDIR "\\test_exclusiv6_1.dat"; + const char *fname2 = BASEDIR "\\test_exclusiv6_2.dat"; + const char *fname3 = BASEDIR "\\test_exclusiv6_3.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_fileinfo qfi; + union smb_setfileinfo sfi; + uint16_t fnum=0; + uint16_t fnum2 = 0; + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname1); + smbcli_unlink(cli1->tree, fname2); + smbcli_unlink(cli1->tree, fname3); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, + cli1->tree); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid.fnum = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname1; + + torture_comment(tctx, "open a file with an exclusive oplock (share " + "mode: none)\n"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK; + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN); + + torture_comment(tctx, "setpathinfo rename info should trigger a break " + "to none\n"); + ZERO_STRUCT(sfi); + sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; + sfi.generic.in.file.path = fname1; + sfi.rename_information.in.overwrite = 0; + sfi.rename_information.in.root_fid = 0; + sfi.rename_information.in.new_name = fname2+strlen(BASEDIR)+1; + + status = smb_raw_setpathinfo(cli2->tree, &sfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + + torture_wait_for_oplock_break(tctx); + CHECK_VAL(break_info.failures, 0); + + if (TARGET_IS_WINXP(tctx)) { + /* XP incorrectly breaks to level2. */ + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + } else { + /* Exclusive oplocks should not be broken on rename. */ + CHECK_VAL(break_info.failures, 0); + CHECK_VAL(break_info.count, 0); + } + + ZERO_STRUCT(qfi); + qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; + qfi.generic.in.file.fnum = fnum; + + status = smb_raw_fileinfo(cli1->tree, tctx, &qfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2); + + /* Try breaking to level2 and then see if rename breaks the level2.*/ + ZERO_STRUCT(break_info); + io.ntcreatex.in.fname = fname2; + status = smb_raw_open(cli2->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum2 = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); + + torture_wait_for_oplock_break(tctx); + CHECK_VAL(break_info.failures, 0); + + if (TARGET_IS_WINXP(tctx)) { + /* XP already broke to level2. */ + CHECK_VAL(break_info.failures, 0); + CHECK_VAL(break_info.count, 0); + } else { + /* Break to level 2 expected. */ + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + } + + ZERO_STRUCT(break_info); + sfi.generic.in.file.path = fname2; + sfi.rename_information.in.overwrite = 0; + sfi.rename_information.in.root_fid = 0; + sfi.rename_information.in.new_name = fname1+strlen(BASEDIR)+1; + + status = smb_raw_setpathinfo(cli2->tree, &sfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + + /* Level2 oplocks are not broken on rename. */ + torture_wait_for_oplock_break(tctx); + CHECK_VAL(break_info.failures, 0); + CHECK_VAL(break_info.count, 0); + + /* Close and re-open file with oplock. */ + smbcli_close(cli1->tree, fnum); + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN); + + torture_comment(tctx, "setfileinfo rename info on a client's own fid " + "should not trigger a break nor a violation\n"); + ZERO_STRUCT(break_info); + ZERO_STRUCT(sfi); + sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION; + sfi.generic.in.file.fnum = fnum; + sfi.rename_information.in.overwrite = 0; + sfi.rename_information.in.root_fid = 0; + sfi.rename_information.in.new_name = fname3+strlen(BASEDIR)+1; + + status = smb_raw_setfileinfo(cli1->tree, &sfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + + torture_wait_for_oplock_break(tctx); + if (TARGET_IS_WINXP(tctx)) { + /* XP incorrectly breaks to level2. */ + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + } else { + CHECK_VAL(break_info.count, 0); + } + + ZERO_STRUCT(qfi); + qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION; + qfi.generic.in.file.fnum = fnum; + + status = smb_raw_fileinfo(cli1->tree, tctx, &qfi); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3); + +done: + smbcli_close(cli1->tree, fnum); + smbcli_close(cli2->tree, fnum2); + + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + static bool test_raw_oplock_batch1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) { const char *fname = BASEDIR "\\test_batch1.dat"; @@ -3693,6 +3863,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx) torture_suite_add_2smb_test(suite, "EXCLUSIVE4", test_raw_oplock_exclusive4); torture_suite_add_2smb_test(suite, "EXCLUSIVE5", test_raw_oplock_exclusive5); torture_suite_add_2smb_test(suite, "EXCLUSIVE6", test_raw_oplock_exclusive6); + torture_suite_add_2smb_test(suite, "EXCLUSIVE7", test_raw_oplock_exclusive7); torture_suite_add_2smb_test(suite, "BATCH1", test_raw_oplock_batch1); torture_suite_add_2smb_test(suite, "BATCH2", test_raw_oplock_batch2); torture_suite_add_2smb_test(suite, "BATCH3", test_raw_oplock_batch3); -- cgit From 551ea65c96e3f9a1aa285c86381d93faba6b4e75 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 Dec 2009 15:30:41 +1100 Subject: Samba4 and LDB requires talloc 2.0.1 reported by ewoud@kohlvanwijngaarden.nl --- source4/lib/ldb/external/libtalloc.m4 | 2 +- source4/min_versions.m4 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/external/libtalloc.m4 b/source4/lib/ldb/external/libtalloc.m4 index 8c63fcc041..dfccaf4fb7 100644 --- a/source4/lib/ldb/external/libtalloc.m4 +++ b/source4/lib/ldb/external/libtalloc.m4 @@ -2,7 +2,7 @@ AC_SUBST(TALLOC_OBJ) AC_SUBST(TALLOC_CFLAGS) AC_SUBST(TALLOC_LIBS) -PKG_CHECK_MODULES(TALLOC, talloc >= 2.0.0, +PKG_CHECK_MODULES(TALLOC, talloc >= 2.0.1, [ ], [ AC_CHECK_HEADER(talloc.h, [ AC_CHECK_LIB(talloc, talloc_init, [TALLOC_LIBS="-ltalloc"])])]) diff --git a/source4/min_versions.m4 b/source4/min_versions.m4 index 5bb3b0b3a9..af8c4dd8fb 100644 --- a/source4/min_versions.m4 +++ b/source4/min_versions.m4 @@ -1,6 +1,6 @@ # Minimum and exact required versions for various libraries # if we use the ones installed in the system. define(TDB_MIN_VERSION,1.2.0) -define(TALLOC_MIN_VERSION,2.0.0) +define(TALLOC_MIN_VERSION,2.0.1) define(LDB_REQUIRED_VERSION,0.9.10) define(TEVENT_REQUIRED_VERSION,0.9.8) -- cgit From 383369e8f204f5a02b6c056f276f14f2f9518044 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 22 Dec 2009 17:21:06 +1100 Subject: s4:auth generate the prototype file in the right place --- source4/auth/ntlm/config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/auth/ntlm/config.mk b/source4/auth/ntlm/config.mk index a0d668f748..82738529cf 100644 --- a/source4/auth/ntlm/config.mk +++ b/source4/auth/ntlm/config.mk @@ -74,7 +74,7 @@ OUTPUT_TYPE = MERGED_OBJ PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSECURITY SAMDB CREDENTIALS auth_OBJ_FILES = $(addprefix $(authsrcdir)/ntlm/, auth.o auth_util.o auth_simple.o) -$(eval $(call proto_header_template,$(authsrcdir)/auth_proto.h,$(auth_OBJ_FILES:.o=.c))) +$(eval $(call proto_header_template,$(authsrcdir)/ntlm/auth_proto.h,$(auth_OBJ_FILES:.o=.c))) # PUBLIC_HEADERS += auth/auth.h -- cgit From 0809696dbf3f551c0fbd37154025053b55fa07ee Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 14 Dec 2009 20:32:47 +1100 Subject: s4:auth Change 'get_challenge' API to be more like Samba3 It is just easier to fill in the known to be 8 byte challenge than stuff about with allocated pointers. Andrew Bartlett --- source4/auth/auth.h | 6 +++--- source4/auth/ntlm/auth.c | 25 ++++++++----------------- source4/auth/ntlm/auth_proto.h | 2 +- source4/auth/ntlm/auth_server.c | 7 +++++-- source4/auth/ntlm/auth_util.c | 12 ++++++------ source4/auth/ntlm/auth_winbind.c | 6 +++--- source4/auth/ntlmssp/ntlmssp_server.c | 7 +++++-- source4/smb_server/smb/negprot.c | 5 +---- 8 files changed, 32 insertions(+), 38 deletions(-) (limited to 'source4') diff --git a/source4/auth/auth.h b/source4/auth/auth.h index c31ed2f5fd..c625c87f39 100644 --- a/source4/auth/auth.h +++ b/source4/auth/auth.h @@ -135,7 +135,7 @@ struct auth_operations { * security=server, and makes a number of compromises to allow * that. It is not compatible with being a PDC. */ - NTSTATUS (*get_challenge)(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge); + NTSTATUS (*get_challenge)(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, uint8_t chal[8]); /* Given the user supplied info, check if this backend want to handle the password checking */ @@ -190,7 +190,7 @@ struct auth_context { const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info); - NTSTATUS (*get_challenge)(struct auth_context *auth_ctx, const uint8_t **_chal); + NTSTATUS (*get_challenge)(struct auth_context *auth_ctx, uint8_t chal[8]); bool (*challenge_may_be_modified)(struct auth_context *auth_ctx); @@ -226,7 +226,7 @@ struct ldb_context; struct ldb_dn; struct gensec_security; -NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal); +NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, uint8_t chal[8]); NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, uint32_t logon_parameters, diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c index 5520c9d01f..d0c8ed3a68 100644 --- a/source4/auth/ntlm/auth.c +++ b/source4/auth/ntlm/auth.c @@ -51,42 +51,34 @@ bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) Try to get a challenge out of the various authentication modules. Returns a const char of length 8 bytes. ****************************************************************************/ -_PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal) +_PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, uint8_t chal[8]) { NTSTATUS nt_status; struct auth_method_context *method; - if (auth_ctx->challenge.data.length) { + if (auth_ctx->challenge.data.length == 8) { DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", auth_ctx->challenge.set_by)); - *_chal = auth_ctx->challenge.data.data; + memcpy(chal, auth_ctx->challenge.data.data, 8); return NT_STATUS_OK; } for (method = auth_ctx->methods; method; method = method->next) { - DATA_BLOB challenge = data_blob(NULL,0); - - nt_status = method->ops->get_challenge(method, auth_ctx, &challenge); + nt_status = method->ops->get_challenge(method, auth_ctx, chal); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { continue; } NT_STATUS_NOT_OK_RETURN(nt_status); - if (challenge.length != 8) { - DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n", - (unsigned)challenge.length, method->ops->name)); - return NT_STATUS_INTERNAL_ERROR; - } - - auth_ctx->challenge.data = challenge; + auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); auth_ctx->challenge.set_by = method->ops->name; break; } if (!auth_ctx->challenge.set_by) { - uint8_t chal[8]; generate_random_buffer(chal, 8); auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); @@ -99,7 +91,6 @@ _PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_ DEBUG(10,("auth_get_challenge: challenge set by %s\n", auth_ctx->challenge.set_by)); - *_chal = auth_ctx->challenge.data.data; return NT_STATUS_OK; } @@ -256,7 +247,7 @@ _PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx, /* if all the modules say 'not for me' this is reasonable */ NTSTATUS nt_status; struct auth_method_context *method; - const uint8_t *challenge; + uint8_t chal[8]; struct auth_usersupplied_info *user_info_tmp; struct auth_check_password_request *req = NULL; @@ -283,7 +274,7 @@ _PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx, DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n", user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name)); - nt_status = auth_get_challenge(auth_ctx, &challenge); + nt_status = auth_get_challenge(auth_ctx, chal); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n", (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status))); diff --git a/source4/auth/ntlm/auth_proto.h b/source4/auth/ntlm/auth_proto.h index 572c1a4ca7..5e8c725ea0 100644 --- a/source4/auth/ntlm/auth_proto.h +++ b/source4/auth/ntlm/auth_proto.h @@ -23,7 +23,7 @@ NTSTATUS server_service_auth_init(void); /* The following definitions come from auth/ntlm/auth_util.c */ -NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge); +NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, uint8_t chal[8]); /**************************************************************************** Create an auth_usersupplied_data structure after appropriate mapping. diff --git a/source4/auth/ntlm/auth_server.c b/source4/auth/ntlm/auth_server.c index 12849aa420..ae7b7dd3a8 100644 --- a/source4/auth/ntlm/auth_server.c +++ b/source4/auth/ntlm/auth_server.c @@ -40,7 +40,7 @@ static NTSTATUS server_want_check(struct auth_method_context *ctx, /** * The challenge from the target server, when operating in security=server **/ -static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) +static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, uint8_t chal[8]) { struct smb_composite_connect io; struct smbcli_options smb_options; @@ -88,7 +88,10 @@ static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX ctx->auth_ctx->event_ctx); NT_STATUS_NOT_OK_RETURN(status); - *_blob = io.out.tree->session->transport->negotiate.secblob; + if (io.out.tree->session->transport->negotiate.secblob.length != 8) { + return NT_STATUS_INTERNAL_ERROR; + } + memcpy(chal, io.out.tree->session->transport->negotiate.secblob.data, 8); ctx->private_data = talloc_steal(ctx, io.out.tree->session); return NT_STATUS_OK; } diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c index 5543cbebea..92df0bfe80 100644 --- a/source4/auth/ntlm/auth_util.c +++ b/source4/auth/ntlm/auth_util.c @@ -29,7 +29,7 @@ /* this default function can be used by mostly all backends * which don't want to set a challenge */ -NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge) +NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, uint8_t chal[8]) { /* we don't want to set a challenge */ return NT_STATUS_NOT_IMPLEMENTED; @@ -122,7 +122,7 @@ NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_contex } case AUTH_PASSWORD_HASH: { - const uint8_t *challenge; + uint8_t chal[8]; DATA_BLOB chall_blob; user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); if (!user_info_temp) { @@ -134,12 +134,12 @@ NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_contex *user_info_temp = *user_info_in; user_info_temp->mapped_state = to_state; - nt_status = auth_get_challenge(auth_context, &challenge); + nt_status = auth_get_challenge(auth_context, chal); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } - chall_blob = data_blob_talloc(mem_ctx, challenge, 8); + chall_blob = data_blob_talloc(mem_ctx, chal, 8); if (lp_client_ntlmv2_auth(auth_context->lp_ctx)) { DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx)); DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key; @@ -162,12 +162,12 @@ NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_contex data_blob_free(&ntlmv2_session_key); } else { DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24); - SMBOWFencrypt(user_info_in->password.hash.nt->hash, challenge, blob.data); + SMBOWFencrypt(user_info_in->password.hash.nt->hash, chal, blob.data); user_info_temp->password.response.nt = blob; if (lp_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) { DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24); - SMBOWFencrypt(user_info_in->password.hash.lanman->hash, challenge, blob.data); + SMBOWFencrypt(user_info_in->password.hash.lanman->hash, chal, blob.data); user_info_temp->password.response.lanman = lm_blob; } else { /* if not sending the LM password, send the NT password twice */ diff --git a/source4/auth/ntlm/auth_winbind.c b/source4/auth/ntlm/auth_winbind.c index 568226dd87..173a895390 100644 --- a/source4/auth/ntlm/auth_winbind.c +++ b/source4/auth/ntlm/auth_winbind.c @@ -271,7 +271,7 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx, s->req.in.logon.password= password_info; } else { struct netr_NetworkInfo *network_info; - const uint8_t *challenge; + uint8_t chal[8]; status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE, user_info, &user_info_new); @@ -281,10 +281,10 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx, network_info = talloc(s, struct netr_NetworkInfo); NT_STATUS_HAVE_NO_MEMORY(network_info); - status = auth_get_challenge(ctx->auth_ctx, &challenge); + status = auth_get_challenge(ctx->auth_ctx, chal); NT_STATUS_NOT_OK_RETURN(status); - memcpy(network_info->challenge, challenge, sizeof(network_info->challenge)); + memcpy(network_info->challenge, chal, sizeof(network_info->challenge)); network_info->nt.length = user_info->password.response.nt.length; network_info->nt.data = user_info->password.response.nt.data; diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index 94de920772..281ffbfa6d 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -600,9 +600,12 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, static const uint8_t *auth_ntlmssp_get_challenge(const struct gensec_ntlmssp_state *gensec_ntlmssp_state) { NTSTATUS status; - const uint8_t *chal; + uint8_t *chal = talloc_array(gensec_ntlmssp_state, uint8_t, 8); + if (!chal) { + return NULL; + } - status = gensec_ntlmssp_state->auth_context->get_challenge(gensec_ntlmssp_state->auth_context, &chal); + status = gensec_ntlmssp_state->auth_context->get_challenge(gensec_ntlmssp_state->auth_context, chal); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("auth_ntlmssp_get_challenge: failed to get challenge: %s\n", nt_errstr(status))); diff --git a/source4/smb_server/smb/negprot.c b/source4/smb_server/smb/negprot.c index ab763e39c3..fe6cd68f6e 100644 --- a/source4/smb_server/smb/negprot.c +++ b/source4/smb_server/smb/negprot.c @@ -33,7 +33,6 @@ static NTSTATUS get_challenge(struct smbsrv_connection *smb_conn, uint8_t buff[8]) { NTSTATUS nt_status; - const uint8_t *challenge; /* muliple negprots are not premitted */ if (smb_conn->negotiate.auth_context) { @@ -53,14 +52,12 @@ static NTSTATUS get_challenge(struct smbsrv_connection *smb_conn, uint8_t buff[8 return nt_status; } - nt_status = auth_get_challenge(smb_conn->negotiate.auth_context, &challenge); + nt_status = auth_get_challenge(smb_conn->negotiate.auth_context, buff); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("auth_get_challenge() returned %s", nt_errstr(nt_status))); return nt_status; } - memcpy(buff, challenge, 8); - return NT_STATUS_OK; } -- cgit From 585900deb58944f35bdf03c0b8cba3509d5b0076 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 8 Dec 2009 16:50:18 +1100 Subject: s4:gensec Don't give a warning when Windows client connects with NTLM We have had the workaround for a long time, but at the time the log warnings remained. Andrew Bartlett --- source4/auth/ntlmssp/ntlmssp_sign.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp_sign.c b/source4/auth/ntlmssp/ntlmssp_sign.c index 957d0a8fbc..9e0d80f788 100644 --- a/source4/auth/ntlmssp/ntlmssp_sign.c +++ b/source4/auth/ntlmssp/ntlmssp_sign.c @@ -171,7 +171,7 @@ NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security, NTLMSSP_RECEIVE, &local_sig, true); if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status))); + DEBUG(0, ("NTLMSSP packet sig creation failed with %s\n", nt_errstr(nt_status))); return nt_status; } @@ -179,26 +179,25 @@ NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security, if (local_sig.length != sig->length || memcmp(local_sig.data, sig->data, sig->length) != 0) { - DEBUG(5, ("BAD SIG NTLM2: wanted signature over %llu bytes of input:\n", (unsigned long long)pdu_length)); - dump_data(5, local_sig.data, local_sig.length); + + DEBUG(10, ("BAD SIG NTLM2: wanted signature over %llu bytes of input:\n", (unsigned long long)pdu_length)); + dump_data(10, local_sig.data, local_sig.length); - DEBUG(5, ("BAD SIG: got signature over %llu bytes of input:\n", (unsigned long long)pdu_length)); - dump_data(5, sig->data, sig->length); + DEBUG(10, ("BAD SIG: got signature over %llu bytes of input:\n", (unsigned long long)pdu_length)); + dump_data(10, sig->data, sig->length); - DEBUG(1, ("NTLMSSP NTLM2 packet check failed due to invalid signature on %llu bytes of input!\n", (unsigned long long)pdu_length)); return NT_STATUS_ACCESS_DENIED; } } else { if (local_sig.length != sig->length || memcmp(local_sig.data + 8, sig->data + 8, sig->length - 8) != 0) { - DEBUG(5, ("BAD SIG NTLM1: wanted signature of %llu bytes of input:\n", (unsigned long long)length)); + DEBUG(10, ("BAD SIG NTLM1: wanted signature of %llu bytes of input:\n", (unsigned long long)length)); dump_data(5, local_sig.data, local_sig.length); - DEBUG(5, ("BAD SIG: got signature of %llu bytes of input:\n", (unsigned long long)length)); - dump_data(5, sig->data, sig->length); + DEBUG(10, ("BAD SIG: got signature of %llu bytes of input:\n", (unsigned long long)length)); + dump_data(10, sig->data, sig->length); - DEBUG(1, ("NTLMSSP NTLM1 packet check failed due to invalid signature on %llu bytes of input:\n", (unsigned long long)length)); return NT_STATUS_ACCESS_DENIED; } } @@ -281,6 +280,7 @@ NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security, const uint8_t *whole_pdu, size_t pdu_length, const DATA_BLOB *sig) { + NTSTATUS status; struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data; if (!gensec_ntlmssp_state->session_key.length) { DEBUG(3, ("NO session key, cannot unseal packet\n")); @@ -294,7 +294,12 @@ NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security, arcfour_crypt_sbox(gensec_ntlmssp_state->crypt.ntlm.arcfour_state, data, length); } dump_data_pw("ntlmssp clear data\n", data, length); - return gensec_ntlmssp_check_packet(gensec_security, sig_mem_ctx, data, length, whole_pdu, pdu_length, sig); + status = gensec_ntlmssp_check_packet(gensec_security, sig_mem_ctx, data, length, whole_pdu, pdu_length, sig); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("NTLMSSP packet check for unseal failed due to invalid signature on %llu bytes of input:\n", (unsigned long long)length)); + } + return status; } /** @@ -585,6 +590,10 @@ NTSTATUS gensec_ntlmssp_unwrap(struct gensec_security *gensec_security, status = check_status; } } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("NTLMSSP packet check for unwrap failed due to invalid signature\n")); + } return status; } else { *out = *in; -- cgit From 3bd4f6792c63fffec66548ae5cfde60e45f865fa Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 22 Dec 2009 20:44:19 +0300 Subject: s4: make ldbadd/ldbmodify/ldbdelete really use the --controls switch --- source4/lib/ldb/tools/config.mk | 13 ++++ source4/lib/ldb/tools/ldbadd.c | 9 ++- source4/lib/ldb/tools/ldbdel.c | 14 ++-- source4/lib/ldb/tools/ldbmodify.c | 14 ++-- source4/lib/ldb/tools/ldbutil.c | 148 ++++++++++++++++++++++++++++++++++++++ source4/lib/ldb/tools/ldbutil.h | 41 +++++++++++ 6 files changed, 230 insertions(+), 9 deletions(-) create mode 100644 source4/lib/ldb/tools/ldbutil.c create mode 100644 source4/lib/ldb/tools/ldbutil.h (limited to 'source4') diff --git a/source4/lib/ldb/tools/config.mk b/source4/lib/ldb/tools/config.mk index 6b57929df0..f0d0e85e6f 100644 --- a/source4/lib/ldb/tools/config.mk +++ b/source4/lib/ldb/tools/config.mk @@ -1,3 +1,13 @@ +################################################ +# Start SUBSYSTEM LIBLDB_UTIL +[SUBSYSTEM::LIBLDB_UTIL] +CFLAGS = -I$(ldbsrcdir) -I$(ldbsrcdir)/include +PUBLIC_DEPENDENCIES = LIBLDB +# End SUBSYSTEM LIBLDB_UTIL +################################################ + +LIBLDB_UTIL_OBJ_FILES = $(ldbsrcdir)/tools/ldbutil.o + ################################################ # Start SUBSYSTEM LIBLDB_CMDLINE [SUBSYSTEM::LIBLDB_CMDLINE] @@ -14,6 +24,7 @@ LIBLDB_CMDLINE_OBJ_FILES = $(ldbsrcdir)/tools/cmdline.o [BINARY::ldbadd] INSTALLDIR = BINDIR PRIVATE_DEPENDENCIES = \ + LIBLDB_UTIL \ LIBLDB_CMDLINE LIBCLI_RESOLVE # End BINARY ldbadd ################################################ @@ -28,6 +39,7 @@ MANPAGES += $(ldbsrcdir)/man/ldbadd.1 [BINARY::ldbdel] INSTALLDIR = BINDIR PRIVATE_DEPENDENCIES = \ + LIBLDB_UTIL \ LIBLDB_CMDLINE # End BINARY ldbdel ################################################ @@ -41,6 +53,7 @@ MANPAGES += $(ldbsrcdir)/man/ldbdel.1 [BINARY::ldbmodify] INSTALLDIR = BINDIR PRIVATE_DEPENDENCIES = \ + LIBLDB_UTIL \ LIBLDB_CMDLINE # End BINARY ldbmodify ################################################ diff --git a/source4/lib/ldb/tools/ldbadd.c b/source4/lib/ldb/tools/ldbadd.c index a87c99aaee..4ff07a5bef 100644 --- a/source4/lib/ldb/tools/ldbadd.c +++ b/source4/lib/ldb/tools/ldbadd.c @@ -33,6 +33,7 @@ #include "ldb.h" #include "tools/cmdline.h" +#include "ldbutil.h" static int failures; static struct ldb_cmdline *options; @@ -53,6 +54,12 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) { struct ldb_ldif *ldif; int ret = LDB_SUCCESS; + struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); + if (options->controls != NULL && req_ctrls== NULL) { + printf("parsing controls failed: %s\n", ldb_errstring(ldb)); + return -1; + } + while ((ldif = ldb_ldif_read_file(ldb, f))) { if (ldif->changetype != LDB_CHANGETYPE_ADD && @@ -63,7 +70,7 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) ldif->msg = ldb_msg_canonicalize(ldb, ldif->msg); - ret = ldb_add(ldb, ldif->msg); + ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls); if (ret != LDB_SUCCESS) { fprintf(stderr, "ERR: \"%s\" on DN %s\n", ldb_errstring(ldb), ldb_dn_get_linearized(ldif->msg->dn)); diff --git a/source4/lib/ldb/tools/ldbdel.c b/source4/lib/ldb/tools/ldbdel.c index 5740f22503..4180afb99c 100644 --- a/source4/lib/ldb/tools/ldbdel.c +++ b/source4/lib/ldb/tools/ldbdel.c @@ -33,6 +33,7 @@ #include "ldb.h" #include "tools/cmdline.h" +#include "ldbutil.h" static int dn_cmp(const void *p1, const void *p2) { @@ -42,7 +43,7 @@ static int dn_cmp(const void *p1, const void *p2) return ldb_dn_compare(msg1->dn, msg2->dn); } -static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn) +static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn,struct ldb_control **req_ctrls) { int ret, i, total=0; const char *attrs[] = { NULL }; @@ -55,7 +56,7 @@ static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn) qsort(res->msgs, res->count, sizeof(res->msgs[0]), dn_cmp); for (i = 0; i < res->count; i++) { - if (ldb_delete(ldb, res->msgs[i]->dn) == 0) { + if (ldb_delete_ctrl(ldb, res->msgs[i]->dn,req_ctrls) == 0) { total++; } else { printf("Failed to delete '%s' - %s\n", @@ -95,6 +96,11 @@ int main(int argc, const char **argv) usage(); exit(1); } + struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); + if (options->controls != NULL && req_ctrls== NULL) { + printf("parsing controls failed: %s\n", ldb_errstring(ldb)); + return -1; + } for (i=0;iargc;i++) { struct ldb_dn *dn; @@ -105,9 +111,9 @@ int main(int argc, const char **argv) exit(1); } if (options->recursive) { - ret = ldb_delete_recursive(ldb, dn); + ret = ldb_delete_recursive(ldb, dn,req_ctrls); } else { - ret = ldb_delete(ldb, dn); + ret = ldb_delete_ctrl(ldb, dn,req_ctrls); if (ret == 0) { printf("Deleted 1 record\n"); } diff --git a/source4/lib/ldb/tools/ldbmodify.c b/source4/lib/ldb/tools/ldbmodify.c index 4936880d09..575658600c 100644 --- a/source4/lib/ldb/tools/ldbmodify.c +++ b/source4/lib/ldb/tools/ldbmodify.c @@ -33,6 +33,7 @@ #include "ldb.h" #include "tools/cmdline.h" +#include "ldbutil.h" static int failures; static struct ldb_cmdline *options; @@ -52,18 +53,23 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) { struct ldb_ldif *ldif; int ret = LDB_SUCCESS; - + struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); + if (options->controls != NULL && req_ctrls== NULL) { + printf("parsing controls failed: %s\n", ldb_errstring(ldb)); + return -1; + } + while ((ldif = ldb_ldif_read_file(ldb, f))) { switch (ldif->changetype) { case LDB_CHANGETYPE_NONE: case LDB_CHANGETYPE_ADD: - ret = ldb_add(ldb, ldif->msg); + ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls); break; case LDB_CHANGETYPE_DELETE: - ret = ldb_delete(ldb, ldif->msg->dn); + ret = ldb_delete_ctrl(ldb, ldif->msg->dn,req_ctrls); break; case LDB_CHANGETYPE_MODIFY: - ret = ldb_modify(ldb, ldif->msg); + ret = ldb_modify_ctrl(ldb, ldif->msg,req_ctrls); break; } if (ret != LDB_SUCCESS) { diff --git a/source4/lib/ldb/tools/ldbutil.c b/source4/lib/ldb/tools/ldbutil.c new file mode 100644 index 0000000000..3d03da6dd0 --- /dev/null +++ b/source4/lib/ldb/tools/ldbutil.c @@ -0,0 +1,148 @@ +/* + ldb database library utility + + Copyright (C) Matthieu Patou 2009 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +/* + * Name: ldb + * + * Description: Common function used by ldb_add/ldb_modify/ldb_delete + * + * Author: Matthieu Patou + */ + +#include "ldb.h" + +/* autostarts a transacion if none active */ +static int ldb_do_autotransaction(struct ldb_context *ldb, + struct ldb_request *req) +{ + int ret; + + ret = ldb_transaction_start(ldb); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_request(ldb, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret == LDB_SUCCESS) { + return ldb_transaction_commit(ldb); + } + ldb_transaction_cancel(ldb); + + if (ldb_errstring(ldb) == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, "%s (%d)", ldb_strerror(ret), ret); + } + + return ret; +} +/* + Same as ldb_add but accept control +*/ +int ldb_add_ctrl(struct ldb_context *ldb, + const struct ldb_message *message, + struct ldb_control **controls) +{ + struct ldb_request *req; + int ret; + + ret = ldb_msg_sanity_check(ldb, message); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_build_add_req(&req, ldb, ldb, + message, + controls, + NULL, + ldb_op_default_callback, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + /* do request and autostart a transaction */ + ret = ldb_do_autotransaction(ldb, req); + + talloc_free(req); + return ret; +} + +/* + same as ldb_delete but accept control +*/ +int ldb_delete_ctrl(struct ldb_context *ldb, struct ldb_dn *dn, + struct ldb_control **controls) +{ + struct ldb_request *req; + int ret; + + ret = ldb_build_del_req(&req, ldb, ldb, + dn, + controls, + NULL, + ldb_op_default_callback, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + /* do request and autostart a transaction */ + ret = ldb_do_autotransaction(ldb, req); + + talloc_free(req); + return ret; +} + + +/* + same as ldb_modify, but accepts controls +*/ +int ldb_modify_ctrl(struct ldb_context *ldb, + const struct ldb_message *message, + struct ldb_control **controls) +{ + struct ldb_request *req; + int ret; + + ret = ldb_msg_sanity_check(ldb, message); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_build_mod_req(&req, ldb, ldb, + message, + controls, + NULL, + ldb_op_default_callback, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + /* do request and autostart a transaction */ + ret = ldb_do_autotransaction(ldb, req); + + talloc_free(req); + return ret; +} diff --git a/source4/lib/ldb/tools/ldbutil.h b/source4/lib/ldb/tools/ldbutil.h new file mode 100644 index 0000000000..7747dbec64 --- /dev/null +++ b/source4/lib/ldb/tools/ldbutil.h @@ -0,0 +1,41 @@ +/* + ldb database library utility header file + + Copyright (C) Matthieu Patou 2009 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +/* + * Name: ldb + * + * Description: Common function used by ldb_add/ldb_modify/ldb_delete + * + * Author: Matthieu Patou + */ + +#include "ldb.h" + +int ldb_add_ctrl(struct ldb_context *ldb, + const struct ldb_message *message, + struct ldb_control **controls); +int ldb_delete_ctrl(struct ldb_context *ldb, struct ldb_dn *dn, + struct ldb_control **controls); +int ldb_modify_ctrl(struct ldb_context *ldb, + const struct ldb_message *message, + struct ldb_control **controls); -- cgit From 8dc636ad674a11825e9043fc356209bf2e28bcff Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sat, 5 Dec 2009 17:56:35 +0300 Subject: s4: tests controls parsing and using for ldbadd/ldbedit/ldbmodify --- source4/lib/ldb/config.mk | 13 ++++++++++ source4/lib/ldb/tests/sample_module.c | 30 +++++++++++++++++++++- source4/lib/ldb/tests/test-controls.sh | 46 ++++++++++++++++++++++++++++++++++ source4/lib/ldb/tests/test-tdb.sh | 2 ++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100755 source4/lib/ldb/tests/test-controls.sh (limited to 'source4') diff --git a/source4/lib/ldb/config.mk b/source4/lib/ldb/config.mk index 4a1f814baa..7d110fc618 100644 --- a/source4/lib/ldb/config.mk +++ b/source4/lib/ldb/config.mk @@ -10,6 +10,19 @@ ldb_asq_OBJ_FILES = $(ldbsrcdir)/modules/asq.o # End MODULE ldb_asq ################################################ +################################################ +# Start MODULE sample_module +[MODULE::sample] +PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT +CFLAGS = -I$(ldbsrcdir)/include +INIT_FUNCTION = LDB_MODULE(sample) +SUBSYSTEM = LIBTESTLDB + +# End MODULE sample_module +################################################ +sample_OBJ_FILES = $(ldbsrcdir)/tests/sample_module.o + + ################################################ # Start MODULE ldb_server_sort [MODULE::ldb_server_sort] diff --git a/source4/lib/ldb/tests/sample_module.c b/source4/lib/ldb/tests/sample_module.c index bbe4419b59..bb7906e7ba 100644 --- a/source4/lib/ldb/tests/sample_module.c +++ b/source4/lib/ldb/tests/sample_module.c @@ -25,12 +25,40 @@ int sample_add(struct ldb_module *mod, struct ldb_request *req) { + struct ldb_control *control; + struct ldb_control *controls; ldb_msg_add_fmt(req->op.add.message, "touchedBy", "sample"); - return ldb_next_request(mod, req); + + /* check if there's a relax control */ + control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID); + if (control == NULL) { + /* not found go on */ + return ldb_next_request(mod, req); + } else { + return LDB_ERR_UNWILLING_TO_PERFORM; + } +} + +int sample_modify(struct ldb_module *mod, struct ldb_request *req) +{ + struct ldb_control *control; + struct ldb_control *controls; + + /* check if there's a relax control */ + control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID); + if (control == NULL) { + /* not found go on */ + return ldb_next_request(mod, req); + } else { + return LDB_ERR_UNWILLING_TO_PERFORM; + } } + const struct ldb_module_ops ldb_sample_module_ops = { .name = "sample", .add = sample_add, + .del = sample_modify, + .modify = sample_modify, }; diff --git a/source4/lib/ldb/tests/test-controls.sh b/source4/lib/ldb/tests/test-controls.sh new file mode 100755 index 0000000000..db139bbec7 --- /dev/null +++ b/source4/lib/ldb/tests/test-controls.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +if [ -n "$TEST_DATA_PREFIX" ]; then + LDB_URL="$TEST_DATA_PREFIX/tdbtest.ldb" +else + LDB_URL="tdbtest.ldb" +fi +export LDB_URL + +PATH=bin:$PATH +export PATH + +rm -f $LDB_URL* +LDB_MODULES_PATH=`dirname $0`/../../../bin/modules/testldb +echo $LDB_MODULES_PATH + +echo "LDB_URL: $LDB_URL" +cat < Date: Wed, 23 Dec 2009 10:28:14 -0500 Subject: s4: Fix the build --- source4/lib/ldb/tools/ldbutil.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4') diff --git a/source4/lib/ldb/tools/ldbutil.c b/source4/lib/ldb/tools/ldbutil.c index 3d03da6dd0..5f7ea894df 100644 --- a/source4/lib/ldb/tools/ldbutil.c +++ b/source4/lib/ldb/tools/ldbutil.c @@ -30,6 +30,7 @@ */ #include "ldb.h" +#include "ldb_module.h" /* autostarts a transacion if none active */ static int ldb_do_autotransaction(struct ldb_context *ldb, -- cgit From 7e8b042b07f374fae9f57feb7f16c3bcd5abf20c Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 23 Dec 2009 10:33:26 -0500 Subject: s4:ldb Fix declaration in the middle of the code --- source4/lib/ldb/tools/ldbdel.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/tools/ldbdel.c b/source4/lib/ldb/tools/ldbdel.c index 4180afb99c..4238f35067 100644 --- a/source4/lib/ldb/tools/ldbdel.c +++ b/source4/lib/ldb/tools/ldbdel.c @@ -84,9 +84,10 @@ static void usage(void) int main(int argc, const char **argv) { + struct ldb_control **req_ctrls; + struct ldb_cmdline *options; struct ldb_context *ldb; int ret = 0, i; - struct ldb_cmdline *options; ldb = ldb_init(NULL, NULL); @@ -96,7 +97,8 @@ int main(int argc, const char **argv) usage(); exit(1); } - struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); + + req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls); if (options->controls != NULL && req_ctrls== NULL) { printf("parsing controls failed: %s\n", ldb_errstring(ldb)); return -1; -- cgit From da27d4e465e682b4f54157f4385c98f9b34dd934 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 23 Dec 2009 15:08:02 -0500 Subject: s4:cleanups remove trailing spaces and tabs --- source4/kdc/hdb-samba4.c | 239 ++++++++++++++++++++++++----------------------- 1 file changed, 120 insertions(+), 119 deletions(-) (limited to 'source4') diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c index 2418e5c63f..2f3c30c283 100644 --- a/source4/kdc/hdb-samba4.c +++ b/source4/kdc/hdb-samba4.c @@ -53,13 +53,13 @@ #include "kdc/kdc.h" #include "../lib/crypto/md4.h" -enum hdb_samba4_ent_type -{ HDB_SAMBA4_ENT_TYPE_CLIENT, HDB_SAMBA4_ENT_TYPE_SERVER, +enum hdb_samba4_ent_type +{ HDB_SAMBA4_ENT_TYPE_CLIENT, HDB_SAMBA4_ENT_TYPE_SERVER, HDB_SAMBA4_ENT_TYPE_KRBTGT, HDB_SAMBA4_ENT_TYPE_TRUST, HDB_SAMBA4_ENT_TYPE_ANY }; enum trust_direction { UNKNOWN = 0, - INBOUND = LSA_TRUST_DIRECTION_INBOUND, + INBOUND = LSA_TRUST_DIRECTION_INBOUND, OUTBOUND = LSA_TRUST_DIRECTION_OUTBOUND }; @@ -93,7 +93,7 @@ static KerberosTime ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, con return timegm(&tm); } -static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum hdb_samba4_ent_type ent_type) +static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum hdb_samba4_ent_type ent_type) { HDBFlags flags = int2HDBFlags(0); @@ -115,7 +115,7 @@ static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum h } flags.invalid = 0; } - + if (userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) { if (ent_type == HDB_SAMBA4_ENT_TYPE_CLIENT || ent_type == HDB_SAMBA4_ENT_TYPE_ANY) { flags.client = 1; @@ -166,7 +166,7 @@ static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum h } if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) { flags.ok_as_delegate = 1; - } + } if (!(userAccountControl & UF_NOT_DELEGATED)) { flags.forwardable = 1; flags.proxiable = 1; @@ -334,7 +334,7 @@ static krb5_error_code hdb_samba4_message2entry_keys(krb5_context context, ret = krb5_keyblock_init(context, ENCTYPE_ARCFOUR_HMAC, - hash->hash, sizeof(hash->hash), + hash->hash, sizeof(hash->hash), &key.key); if (ret) { goto out; @@ -490,8 +490,8 @@ out: /* * Construct an hdb_entry from a directory entry. */ -static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, - struct loadparm_context *lp_ctx, +static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, + struct loadparm_context *lp_ctx, TALLOC_CTX *mem_ctx, krb5_const_principal principal, enum hdb_samba4_ent_type ent_type, struct ldb_dn *realm_dn, @@ -514,7 +514,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL); computer_val.data = discard_const_p(uint8_t,"computer"); computer_val.length = strlen((const char *)computer_val.data); - + if (!samAccountName) { ret = ENOENT; krb5_set_error_message(context, ret, "hdb_samba4_message2entry: no samAccountName present"); @@ -522,7 +522,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, } objectclasses = ldb_msg_find_element(msg, "objectClass"); - + if (objectclasses && ldb_msg_find_val(objectclasses, &computer_val)) { is_computer = TRUE; } @@ -534,7 +534,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, krb5_set_error_message(context, ret, "talloc_strdup: out of memory"); goto out; } - + p = talloc(mem_ctx, struct hdb_samba4_private); if (!p) { ret = ENOMEM; @@ -557,7 +557,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); - + entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal))); if (ent_type == HDB_SAMBA4_ENT_TYPE_ANY && principal == NULL) { krb5_make_principal(context, &entry_ex->entry.principal, realm, samAccountName, NULL); @@ -573,7 +573,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, * the client-specified realm. This code attempts to * replace the client principal's realm with the one * we determine from our records */ - + /* this has to be with malloc() */ krb5_principal_set_realm(context, entry_ex->entry.principal, realm); } @@ -598,19 +598,19 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, * of the Heimdal KDC. They are stored in a the traditional * DB for audit purposes, and still form part of the structure * we must return */ - + /* use 'whenCreated' */ entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0); /* use '???' */ entry_ex->entry.created_by.principal = NULL; - + entry_ex->entry.modified_by = (Event *) malloc(sizeof(Event)); if (entry_ex->entry.modified_by == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } - + /* use 'whenChanged' */ entry_ex->entry.modified_by->time = ldb_msg_find_krb5time_ldap_time(msg, "whenChanged", 0); /* use '???' */ @@ -661,7 +661,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, } else { NTTIME must_change_time - = samdb_result_force_password_change((struct ldb_context *)db->hdb_db, mem_ctx, + = samdb_result_force_password_change((struct ldb_context *)db->hdb_db, mem_ctx, realm_dn, msg); if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) { entry_ex->entry.pw_end = NULL; @@ -722,7 +722,7 @@ static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, p->msg = talloc_steal(p, msg); p->samdb = (struct ldb_context *)db->hdb_db; - + out: if (ret != 0) { /* This doesn't free ent itself, that is for the eventual caller to do */ @@ -737,7 +737,7 @@ out: /* * Construct an hdb_entry from a directory entry. */ -static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB *db, +static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB *db, struct loadparm_context *lp_ctx, TALLOC_CTX *mem_ctx, krb5_const_principal principal, enum trust_direction direction, @@ -745,7 +745,7 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB struct ldb_message *msg, hdb_entry_ex *entry_ex) { - + const char *dnsdomain; char *realm; DATA_BLOB password_utf16; @@ -843,16 +843,16 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB ret = ENOMEM; goto out; } - + ret = krb5_keyblock_init(context, ENCTYPE_ARCFOUR_HMAC, - password_hash.hash, sizeof(password_hash.hash), + password_hash.hash, sizeof(password_hash.hash), &key.key); - + entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key; entry_ex->entry.keys.len++; } - + entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal))); ret = copy_Principal(principal, entry_ex->entry.principal); @@ -860,13 +860,13 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB krb5_clear_error_message(context); goto out; } - + /* While we have copied the client principal, tests * show that Win2k3 returns the 'corrected' realm, not * the client-specified realm. This code attempts to * replace the client principal's realm with the one * we determine from our records */ - + krb5_principal_set_realm(context, entry_ex->entry.principal, realm); entry_ex->entry.flags = int2HDBFlags(0); entry_ex->entry.flags.immutable = 1; @@ -875,7 +875,7 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB entry_ex->entry.flags.require_preauth = 1; entry_ex->entry.pw_end = NULL; - + entry_ex->entry.max_life = NULL; entry_ex->entry.max_renew = NULL; @@ -902,7 +902,7 @@ static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB p->msg = talloc_steal(p, msg); p->samdb = (struct ldb_context *)db->hdb_db; - + out: if (ret != 0) { /* This doesn't free ent itself, that is for the eventual caller to do */ @@ -915,7 +915,7 @@ out: } -static krb5_error_code hdb_samba4_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx, +static krb5_error_code hdb_samba4_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx, TALLOC_CTX *mem_ctx, const char *realm, struct ldb_dn *realm_dn, @@ -959,7 +959,7 @@ static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags, krb5_warnx(context, "hdb_samba4_open: use of a master key incompatible with LDB\n"); krb5_set_error_message(context, ret, "hdb_samba4_open: use of a master key incompatible with LDB\n"); return ret; - } + } return 0; } @@ -984,25 +984,25 @@ static krb5_error_code hdb_samba4_rename(krb5_context context, HDB *db, const ch return HDB_ERR_DB_INUSE; } -static krb5_error_code hdb_samba4_lookup_client(krb5_context context, HDB *db, - struct loadparm_context *lp_ctx, - TALLOC_CTX *mem_ctx, +static krb5_error_code hdb_samba4_lookup_client(krb5_context context, HDB *db, + struct loadparm_context *lp_ctx, + TALLOC_CTX *mem_ctx, krb5_const_principal principal, const char **attrs, - struct ldb_dn **realm_dn, + struct ldb_dn **realm_dn, struct ldb_message **msg) { NTSTATUS nt_status; char *principal_string; krb5_error_code ret; ret = krb5_unparse_name(context, principal, &principal_string); - + if (ret != 0) { return ret; } - + nt_status = sam_get_results_principal((struct ldb_context *)db->hdb_db, - mem_ctx, principal_string, attrs, + mem_ctx, principal_string, attrs, realm_dn, msg); free(principal_string); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) { @@ -1012,13 +1012,13 @@ static krb5_error_code hdb_samba4_lookup_client(krb5_context context, HDB *db, } else if (!NT_STATUS_IS_OK(nt_status)) { return EINVAL; } - + return ret; } -static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db, - struct loadparm_context *lp_ctx, - TALLOC_CTX *mem_ctx, +static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db, + struct loadparm_context *lp_ctx, + TALLOC_CTX *mem_ctx, krb5_const_principal principal, unsigned flags, hdb_entry_ex *entry_ex) { @@ -1026,22 +1026,22 @@ static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db, krb5_error_code ret; struct ldb_message *msg = NULL; - ret = hdb_samba4_lookup_client(context, db, lp_ctx, - mem_ctx, principal, user_attrs, + ret = hdb_samba4_lookup_client(context, db, lp_ctx, + mem_ctx, principal, user_attrs, &realm_dn, &msg); if (ret != 0) { return ret; } - - ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx, + + ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx, principal, HDB_SAMBA4_ENT_TYPE_CLIENT, realm_dn, msg, entry_ex); return ret; } -static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db, - struct loadparm_context *lp_ctx, - TALLOC_CTX *mem_ctx, +static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db, + struct loadparm_context *lp_ctx, + TALLOC_CTX *mem_ctx, krb5_const_principal principal, unsigned flags, hdb_entry_ex *entry_ex) @@ -1062,18 +1062,18 @@ static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db, if (lp_is_my_domain_or_realm(lp_ctx, principal->realm) && lp_is_my_domain_or_realm(lp_ctx, principal->name.name_string.val[1])) { - /* us */ + /* us */ /* Cludge, cludge cludge. If the realm part of krbtgt/realm, * is in our db, then direct the caller at our primary * krbtgt */ int lret; char *realm_fixed; - - lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx, + + lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx, realm_dn, LDB_SCOPE_SUBTREE, - &msg, krbtgt_attrs, - "(&(objectClass=user)(samAccountName=krbtgt))"); + &msg, krbtgt_attrs, + "(&(objectClass=user)(samAccountName=krbtgt))"); if (lret == LDB_ERR_NO_SUCH_OBJECT) { krb5_warnx(context, "hdb_samba4_fetch: could not find own KRBTGT in DB!"); krb5_set_error_message(context, HDB_ERR_NOENTRY, "hdb_samba4_fetch: could not find own KRBTGT in DB!"); @@ -1083,19 +1083,19 @@ static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db, krb5_set_error_message(context, HDB_ERR_NOENTRY, "hdb_samba4_fetch: could not find own KRBTGT in DB: %s", ldb_errstring(db->hdb_db)); return HDB_ERR_NOENTRY; } - + realm_fixed = strupper_talloc(mem_ctx, lp_realm(lp_ctx)); if (!realm_fixed) { ret = ENOMEM; krb5_set_error_message(context, ret, "strupper_talloc: out of memory"); return ret; } - + ret = krb5_copy_principal(context, principal, &alloc_principal); if (ret) { return ret; } - + free(alloc_principal->name.name_string.val[1]); alloc_principal->name.name_string.val[1] = strdup(realm_fixed); talloc_free(realm_fixed); @@ -1106,11 +1106,11 @@ static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db, } principal = alloc_principal; - ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx, - principal, HDB_SAMBA4_ENT_TYPE_KRBTGT, + ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx, + principal, HDB_SAMBA4_ENT_TYPE_KRBTGT, realm_dn, msg, entry_ex); if (ret != 0) { - krb5_warnx(context, "hdb_samba4_fetch: self krbtgt message2entry failed"); + krb5_warnx(context, "hdb_samba4_fetch: self krbtgt message2entry failed"); } return ret; @@ -1132,35 +1132,35 @@ static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db, } /* Trusted domains are under CN=system */ - - ret = hdb_samba4_lookup_trust(context, (struct ldb_context *)db->hdb_db, - mem_ctx, + + ret = hdb_samba4_lookup_trust(context, (struct ldb_context *)db->hdb_db, + mem_ctx, realm, realm_dn, &msg); - + if (ret != 0) { krb5_warnx(context, "hdb_samba4_fetch: could not find principal in DB"); krb5_set_error_message(context, ret, "hdb_samba4_fetch: could not find principal in DB"); return ret; } - - ret = hdb_samba4_trust_message2entry(context, db, lp_ctx, mem_ctx, - principal, direction, + + ret = hdb_samba4_trust_message2entry(context, db, lp_ctx, mem_ctx, + principal, direction, realm_dn, msg, entry_ex); if (ret != 0) { - krb5_warnx(context, "hdb_samba4_fetch: trust_message2entry failed"); + krb5_warnx(context, "hdb_samba4_fetch: trust_message2entry failed"); } return ret; - + /* we should lookup trusted domains */ return HDB_ERR_NOENTRY; } } -static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db, +static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db, struct loadparm_context *lp_ctx, - TALLOC_CTX *mem_ctx, + TALLOC_CTX *mem_ctx, krb5_const_principal principal, const char **attrs, struct ldb_dn **realm_dn, @@ -1174,35 +1174,35 @@ static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db, NTSTATUS nt_status; struct ldb_dn *user_dn; char *principal_string; - - ret = krb5_unparse_name_flags(context, principal, - KRB5_PRINCIPAL_UNPARSE_NO_REALM, + + ret = krb5_unparse_name_flags(context, principal, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, &principal_string); if (ret != 0) { return ret; } - + /* At this point we may find the host is known to be * in a different realm, so we should generate a * referral instead */ nt_status = crack_service_principal_name((struct ldb_context *)db->hdb_db, - mem_ctx, principal_string, + mem_ctx, principal_string, &user_dn, realm_dn); free(principal_string); - + if (!NT_STATUS_IS_OK(nt_status)) { return HDB_ERR_NOENTRY; } - + ldb_ret = gendb_search_single_extended_dn((struct ldb_context *)db->hdb_db, - mem_ctx, + mem_ctx, user_dn, LDB_SCOPE_BASE, msg, attrs, "(objectClass=*)"); if (ldb_ret != LDB_SUCCESS) { return HDB_ERR_NOENTRY; } - + } else { int lret; char *filter = NULL; @@ -1210,20 +1210,20 @@ static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db, /* server as client principal case, but we must not lookup userPrincipalNames */ *realm_dn = ldb_get_default_basedn(db->hdb_db); realm = krb5_principal_get_realm(context, principal); - + /* TODO: Check if it is our realm, otherwise give referall */ - + ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &short_princ); - + if (ret != 0) { krb5_set_error_message(context, ret, "hdb_samba4_lookup_principal: could not parse principal"); krb5_warnx(context, "hdb_samba4_lookup_principal: could not parse principal"); return ret; } - - lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx, + + lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx, *realm_dn, LDB_SCOPE_SUBTREE, - msg, attrs, "(&(objectClass=user)(samAccountName=%s))", + msg, attrs, "(&(objectClass=user)(samAccountName=%s))", ldb_binary_encode_string(mem_ctx, short_princ)); free(short_princ); if (lret == LDB_ERR_NO_SUCH_OBJECT) { @@ -1231,7 +1231,7 @@ static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db, return HDB_ERR_NOENTRY; } if (lret != LDB_SUCCESS) { - DEBUG(3, ("Failed single search for for %s - %s\n", + DEBUG(3, ("Failed single search for for %s - %s\n", filter, ldb_errstring(db->hdb_db))); return HDB_ERR_NOENTRY; } @@ -1240,9 +1240,9 @@ static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db, return 0; } -static krb5_error_code hdb_samba4_fetch_server(krb5_context context, HDB *db, +static krb5_error_code hdb_samba4_fetch_server(krb5_context context, HDB *db, struct loadparm_context *lp_ctx, - TALLOC_CTX *mem_ctx, + TALLOC_CTX *mem_ctx, krb5_const_principal principal, unsigned flags, hdb_entry_ex *entry_ex) @@ -1251,23 +1251,23 @@ static krb5_error_code hdb_samba4_fetch_server(krb5_context context, HDB *db, struct ldb_dn *realm_dn; struct ldb_message *msg; - ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, principal, + ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, principal, server_attrs, &realm_dn, &msg); if (ret != 0) { return ret; } - ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx, + ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx, principal, HDB_SAMBA4_ENT_TYPE_SERVER, realm_dn, msg, entry_ex); if (ret != 0) { - krb5_warnx(context, "hdb_samba4_fetch: message2entry failed"); + krb5_warnx(context, "hdb_samba4_fetch: message2entry failed"); } return ret; } - -static krb5_error_code hdb_samba4_fetch(krb5_context context, HDB *db, + +static krb5_error_code hdb_samba4_fetch(krb5_context context, HDB *db, krb5_const_principal principal, unsigned flags, hdb_entry_ex *entry_ex) @@ -1345,9 +1345,9 @@ static krb5_error_code hdb_samba4_seq(krb5_context context, HDB *db, unsigned fl } if (priv->index < priv->count) { - ret = hdb_samba4_message2entry(context, db, priv->lp_ctx, - mem_ctx, - NULL, HDB_SAMBA4_ENT_TYPE_ANY, + ret = hdb_samba4_message2entry(context, db, priv->lp_ctx, + mem_ctx, + NULL, HDB_SAMBA4_ENT_TYPE_ANY, priv->realm_dn, priv->msgs[priv->index++], entry); } else { ret = HDB_ERR_NOENTRY; @@ -1366,7 +1366,7 @@ static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsign hdb_entry_ex *entry) { struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db; - struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"), + struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"), struct loadparm_context); struct hdb_samba4_seq *priv = (struct hdb_samba4_seq *)db->hdb_dbc; char *realm; @@ -1407,7 +1407,7 @@ static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsign talloc_free(priv); return ret; } - + lret = ldb_search(ldb_ctx, priv, &res, priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs, "(objectClass=user)"); @@ -1449,14 +1449,14 @@ static krb5_error_code hdb_samba4_destroy(krb5_context context, HDB *db) /* Check if a given entry may delegate to this target principal * - * This is currently a very nasty hack - allowing only delegation to itself. + * This is currently a very nasty hack - allowing only delegation to itself. */ -krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db, +krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db, hdb_entry_ex *entry, krb5_const_principal target_principal) { struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db; - struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"), + struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"), struct loadparm_context); krb5_error_code ret; krb5_principal enterprise_prinicpal = NULL; @@ -1468,7 +1468,7 @@ krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HD const char *delegation_check_attrs[] = { "objectSid", NULL }; - + TALLOC_CTX *mem_ctx = talloc_named(db, 0, "hdb_samba4_check_constrained_delegation"); if (!mem_ctx) { @@ -1481,12 +1481,12 @@ krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HD /* Need to reparse the enterprise principal to find the real target */ if (target_principal->name.name_string.len != 1) { ret = KRB5_PARSE_MALFORMED; - krb5_set_error_message(context, ret, "hdb_samba4_check_constrained_delegation: request for delegation to enterprise principal with wrong (%d) number of components", - target_principal->name.name_string.len); + krb5_set_error_message(context, ret, "hdb_samba4_check_constrained_delegation: request for delegation to enterprise principal with wrong (%d) number of components", + target_principal->name.name_string.len); talloc_free(mem_ctx); return ret; } - ret = krb5_parse_name(context, target_principal->name.name_string.val[0], + ret = krb5_parse_name(context, target_principal->name.name_string.val[0], &enterprise_prinicpal); if (ret) { talloc_free(mem_ctx); @@ -1495,7 +1495,7 @@ krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HD target_principal = enterprise_prinicpal; } - ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, target_principal, + ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, target_principal, delegation_check_attrs, &realm_dn, &msg); krb5_free_principal(context, enterprise_prinicpal); @@ -1525,12 +1525,12 @@ krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HD * database. Allow a mismatch where they both refer to the same * SID */ -krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db, +krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db, hdb_entry_ex *entry, krb5_const_principal certificate_principal) { struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db; - struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"), + struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"), struct loadparm_context); krb5_error_code ret; struct ldb_dn *realm_dn; @@ -1541,7 +1541,7 @@ krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB * const char *ms_upn_check_attrs[] = { "objectSid", NULL }; - + TALLOC_CTX *mem_ctx = talloc_named(db, 0, "hdb_samba4_check_constrained_delegation"); if (!mem_ctx) { @@ -1550,10 +1550,10 @@ krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB * return ret; } - ret = hdb_samba4_lookup_client(context, db, lp_ctx, + ret = hdb_samba4_lookup_client(context, db, lp_ctx, mem_ctx, certificate_principal, ms_upn_check_attrs, &realm_dn, &msg); - + if (ret != 0) { talloc_free(mem_ctx); return ret; @@ -1579,8 +1579,8 @@ krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB * * (hdb_samba4_create) from the kpasswdd -> krb5 -> keytab_hdb -> hdb * code */ -NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx, - struct tevent_context *ev_ctx, +NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx, + struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, krb5_context context, struct HDB **db) { @@ -1602,7 +1602,7 @@ NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx, * allow us to share the samdb backend context with other parts of the * system. For now we can't as we need to override the * credentials to set CRED_DONT_USE_KERBEROS, which would - * break other users of the system_session */ + * break other users of the system_session */ DEBUG(0,("FIXME: Using new system session for hdb\n")); nt_status = auth_system_session_info(*db, lp_ctx, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { @@ -1614,7 +1614,7 @@ NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx, return NT_STATUS_INTERNAL_ERROR; } #endif - + /* The idea here is very simple. Using Kerberos to * authenticate the KDC to the LDAP server is higly likely to * be circular. @@ -1622,8 +1622,8 @@ NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx, * In future we may set this up to use EXERNAL and SSL * certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME */ - - cli_credentials_set_kerberos_state(session_info->credentials, + + cli_credentials_set_kerberos_state(session_info->credentials, CRED_DONT_USE_KERBEROS); /* Setup the link to LDB */ @@ -1663,6 +1663,7 @@ static krb5_error_code hdb_samba4_create(krb5_context context, struct HDB **db, NTSTATUS nt_status; void *ptr; struct hdb_samba4_context *hdb_samba4_context; + if (sscanf(arg, "&%p", &ptr) != 1) { return EINVAL; } @@ -1686,6 +1687,6 @@ static krb5_error_code hdb_samba4_create(krb5_context context, struct HDB **db, */ struct hdb_method hdb_samba4 = { .interface_version = HDB_INTERFACE_VERSION, - .prefix = "samba4", + .prefix = "samba4", .create = hdb_samba4_create }; -- cgit From 67d1af438467b9c3a9a13cd8a3dd35cddbf152fc Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 23 Dec 2009 15:17:16 -0500 Subject: s4:cleanups More trailing spaces and tabs --- source4/kdc/hdb-samba4.h | 8 +- source4/kdc/kdc.c | 90 ++++++++++---------- source4/kdc/kdc.h | 12 +-- source4/kdc/kpasswdd.c | 216 +++++++++++++++++++++++------------------------ source4/kdc/pac-glue.c | 30 +++---- source4/kdc/pac-glue.h | 6 +- 6 files changed, 181 insertions(+), 181 deletions(-) (limited to 'source4') diff --git a/source4/kdc/hdb-samba4.h b/source4/kdc/hdb-samba4.h index fc2f9c1310..5f85ce188c 100644 --- a/source4/kdc/hdb-samba4.h +++ b/source4/kdc/hdb-samba4.h @@ -1,21 +1,21 @@ -/* +/* Unix SMB/CIFS implementation. KDC structures Copyright (C) Andrew Tridgell 2005 Copyright (C) Andrew Bartlett 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 3 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, see . */ diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c index 2c07f89f17..b2921842e7 100644 --- a/source4/kdc/kdc.c +++ b/source4/kdc/kdc.c @@ -1,4 +1,4 @@ -/* +/* Unix SMB/CIFS implementation. KDC Server startup @@ -11,12 +11,12 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 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, see . */ @@ -42,15 +42,15 @@ #include "librpc/gen_ndr/ndr_misc.h" -/* Disgusting hack to get a mem_ctx and lp_ctx into the hdb plugin, when +/* Disgusting hack to get a mem_ctx and lp_ctx into the hdb plugin, when * used as a keytab */ TALLOC_CTX *hdb_samba4_mem_ctx; struct tevent_context *hdb_samba4_ev_ctx; struct loadparm_context *hdb_samba4_lp_ctx; typedef bool (*kdc_process_fn_t)(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, - DATA_BLOB *input, + TALLOC_CTX *mem_ctx, + DATA_BLOB *input, DATA_BLOB *reply, struct tsocket_address *peer_addr, struct tsocket_address *my_addr, @@ -98,7 +98,7 @@ static NTSTATUS kdc_tcp_recv(void *private_data, DATA_BLOB blob) talloc_steal(tmp_ctx, blob.data); /* Call krb5 */ - input = data_blob_const(blob.data + 4, blob.length - 4); + input = data_blob_const(blob.data + 4, blob.length - 4); ret = kdcconn->kdc_socket->process(kdcconn->kdc_socket->kdc, tmp_ctx, @@ -120,7 +120,7 @@ static NTSTATUS kdc_tcp_recv(void *private_data, DATA_BLOB blob) } RSIVAL(blob.data, 0, reply.length); - memcpy(blob.data + 4, reply.data, reply.length); + memcpy(blob.data + 4, reply.data, reply.length); status = packet_send(kdcconn->packet, blob); if (!NT_STATUS_IS_OK(status)) { @@ -169,8 +169,8 @@ static void kdc_tcp_send(struct stream_connection *conn, uint16_t flags) */ static bool kdc_process(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, - DATA_BLOB *input, + TALLOC_CTX *mem_ctx, + DATA_BLOB *input, DATA_BLOB *reply, struct tsocket_address *peer_addr, struct tsocket_address *my_addr, @@ -197,7 +197,7 @@ static bool kdc_process(struct kdc_server *kdc, DEBUG(10,("Received KDC packet of length %lu from %s\n", (long)input->length - 4, pa)); - ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context, + ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context, kdc->config, input->data, input->length, &k5_reply, @@ -212,7 +212,7 @@ static bool kdc_process(struct kdc_server *kdc, *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length); krb5_data_free(&k5_reply); } else { - *reply = data_blob(NULL, 0); + *reply = data_blob(NULL, 0); } return true; } @@ -421,12 +421,12 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc, return status; } - status = stream_setup_socket(kdc->task->event_ctx, + status = stream_setup_socket(kdc->task->event_ctx, kdc->task->lp_ctx, - model_ops, - &kdc_tcp_stream_ops, - "ip", address, &port, - lp_socket_options(kdc->task->lp_ctx), + model_ops, + &kdc_tcp_stream_ops, + "ip", address, &port, + lp_socket_options(kdc->task->lp_ctx), kdc_socket); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to bind to %s:%u TCP - %s\n", @@ -487,7 +487,7 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_c } num_interfaces = iface_count(ifaces); - + for (i=0; iout.generic_reply = data_blob(NULL, 0); - ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, - lp_iconv_convenience(kdc->task->lp_ctx), + ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, + lp_iconv_convenience(kdc->task->lp_ctx), &pac_validate, (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return NT_STATUS_INVALID_PARAMETER; } - + if (pac_validate.MessageType != 3) { /* We don't implement any other message types - such as certificate validation - yet */ return NT_STATUS_INVALID_PARAMETER; @@ -550,10 +550,10 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, || pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) { return NT_STATUS_INVALID_PARAMETER; } - - srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data, + + srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data, pac_validate.ChecksumLength); - + if (pac_validate.SignatureType == CKSUMTYPE_HMAC_MD5) { etype = ETYPE_ARCFOUR_HMAC_MD5; } else { @@ -564,16 +564,16 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, } } - ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal, + ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal, lp_realm(kdc->task->lp_ctx), - "krbtgt", lp_realm(kdc->task->lp_ctx), + "krbtgt", lp_realm(kdc->task->lp_ctx), NULL); if (ret != 0) { return NT_STATUS_NO_MEMORY; } - ret = kdc->config->db[0]->hdb_fetch(kdc->smb_krb5_context->krb5_context, + ret = kdc->config->db[0]->hdb_fetch(kdc->smb_krb5_context->krb5_context, kdc->config->db[0], principal, HDB_F_GET_KRBTGT | HDB_F_DECRYPT, @@ -582,10 +582,10 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, if (ret != 0) { hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent); krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal); - + return NT_STATUS_LOGON_FAILURE; } - + ret = hdb_enctype2key(kdc->smb_krb5_context->krb5_context, &ent.entry, etype, &key); if (ret != 0) { @@ -595,11 +595,11 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, } keyblock = key->key; - + kdc_sig.type = pac_validate.SignatureType; kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength], pac_validate.SignatureLength); - ret = check_pac_checksum(msg, srv_sig, &kdc_sig, + ret = check_pac_checksum(msg, srv_sig, &kdc_sig, kdc->smb_krb5_context->krb5_context, &keyblock); hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent); @@ -608,7 +608,7 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, if (ret != 0) { return NT_STATUS_LOGON_FAILURE; } - + return NT_STATUS_OK; } @@ -656,21 +656,21 @@ static void kdc_task_init(struct task_server *task) ret = smb_krb5_init_context(kdc, task->event_ctx, task->lp_ctx, &kdc->smb_krb5_context); if (ret) { - DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n", + DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n", error_message(ret))); task_server_terminate(task, "kdc: krb5_init_context failed", true); - return; + return; } krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r); - ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, + ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, &kdc->config); if(ret) { task_server_terminate(task, "kdc: failed to get KDC configuration", true); return; } - + kdc->config->logf = kdc->smb_krb5_context->logf; kdc->config->db = talloc(kdc, struct HDB *); if (!kdc->config->db) { @@ -678,13 +678,13 @@ static void kdc_task_init(struct task_server *task) return; } kdc->config->num_db = 1; - - status = hdb_samba4_create_kdc(kdc, task->event_ctx, task->lp_ctx, - kdc->smb_krb5_context->krb5_context, + + status = hdb_samba4_create_kdc(kdc, task->event_ctx, task->lp_ctx, + kdc->smb_krb5_context->krb5_context, &kdc->config->db[0]); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true); - return; + return; } /* Register hdb-samba4 hooks for use as a keytab */ @@ -692,13 +692,13 @@ static void kdc_task_init(struct task_server *task) kdc->hdb_samba4_context = talloc(kdc, struct hdb_samba4_context); if (!kdc->hdb_samba4_context) { task_server_terminate(task, "kdc: out of memory", true); - return; + return; } kdc->hdb_samba4_context->ev_ctx = task->event_ctx; kdc->hdb_samba4_context->lp_ctx = task->lp_ctx; - ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, + ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, PLUGIN_TYPE_DATA, "hdb", &hdb_samba4); if(ret) { @@ -713,7 +713,7 @@ static void kdc_task_init(struct task_server *task) } /* Registar WinDC hooks */ - ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, + ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, PLUGIN_TYPE_DATA, "windc", &windc_plugin_table); if(ret) { @@ -730,7 +730,7 @@ static void kdc_task_init(struct task_server *task) return; } - status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, + status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, kdc_check_generic_kerberos, kdc); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "nbtd failed to setup monitoring", true); diff --git a/source4/kdc/kdc.h b/source4/kdc/kdc.h index 4a715fd498..b9cf621537 100644 --- a/source4/kdc/kdc.h +++ b/source4/kdc/kdc.h @@ -1,21 +1,21 @@ -/* +/* Unix SMB/CIFS implementation. KDC structures Copyright (C) Andrew Tridgell 2005 Copyright (C) Andrew Bartlett 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 3 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, see . */ @@ -33,8 +33,8 @@ struct tsocket_address; bool kpasswdd_process(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, - DATA_BLOB *input, + TALLOC_CTX *mem_ctx, + DATA_BLOB *input, DATA_BLOB *reply, struct tsocket_address *peer_addr, struct tsocket_address *my_addr, diff --git a/source4/kdc/kpasswdd.c b/source4/kdc/kpasswdd.c index 9b3336a7a1..8406887dad 100644 --- a/source4/kdc/kpasswdd.c +++ b/source4/kdc/kpasswdd.c @@ -1,4 +1,4 @@ -/* +/* Unix SMB/CIFS implementation. kpasswd Server implementation @@ -10,12 +10,12 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 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, see . */ @@ -45,15 +45,15 @@ #endif /* Return true if there is a valid error packet formed in the error_blob */ -static bool kpasswdd_make_error_reply(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, - uint16_t result_code, - const char *error_string, - DATA_BLOB *error_blob) +static bool kpasswdd_make_error_reply(struct kdc_server *kdc, + TALLOC_CTX *mem_ctx, + uint16_t result_code, + const char *error_string, + DATA_BLOB *error_blob) { char *error_string_utf8; size_t len; - + DEBUG(result_code ? 3 : 10, ("kpasswdd: %s\n", error_string)); if (!push_utf8_talloc(mem_ctx, &error_string_utf8, error_string, &len)) { @@ -70,17 +70,17 @@ static bool kpasswdd_make_error_reply(struct kdc_server *kdc, } /* Return true if there is a valid error packet formed in the error_blob */ -static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, - uint16_t result_code, - const char *error_string, - DATA_BLOB *error_blob) +static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc, + TALLOC_CTX *mem_ctx, + uint16_t result_code, + const char *error_string, + DATA_BLOB *error_blob) { bool ret; int kret; DATA_BLOB error_bytes; krb5_data k5_error_bytes, k5_error_blob; - ret = kpasswdd_make_error_reply(kdc, mem_ctx, result_code, error_string, + ret = kpasswdd_make_error_reply(kdc, mem_ctx, result_code, error_string, &error_bytes); if (!ret) { return false; @@ -88,7 +88,7 @@ static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc, k5_error_bytes.data = error_bytes.data; k5_error_bytes.length = error_bytes.length; kret = krb5_mk_error(kdc->smb_krb5_context->krb5_context, - result_code, NULL, &k5_error_bytes, + result_code, NULL, &k5_error_bytes, NULL, NULL, NULL, NULL, &k5_error_blob); if (kret) { return false; @@ -101,21 +101,21 @@ static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc, return true; } -static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, - NTSTATUS status, +static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc, + TALLOC_CTX *mem_ctx, + NTSTATUS status, enum samPwdChangeReason reject_reason, struct samr_DomInfo1 *dominfo, - DATA_BLOB *error_blob) + DATA_BLOB *error_blob) { if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_ACCESSDENIED, "No such user when changing password", error_blob); } if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_ACCESSDENIED, "Not permitted to change password", error_blob); @@ -138,31 +138,31 @@ static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc, dominfo->min_password_length, dominfo->password_history_length); break; } - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_SOFTERROR, reject_string, error_blob); } if (!NT_STATUS_IS_OK(status)) { - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, talloc_asprintf(mem_ctx, "failed to set password: %s", nt_errstr(status)), error_blob); - + } return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_SUCCESS, "Password changed", error_blob); } -/* +/* A user password change - + Return true if there is a valid error packet (or sucess) formed in the error_blob */ static bool kpasswdd_change_password(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, + TALLOC_CTX *mem_ctx, struct auth_session_info *session_info, const DATA_BLOB *password, DATA_BLOB *reply) @@ -174,45 +174,45 @@ static bool kpasswdd_change_password(struct kdc_server *kdc, samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, system_session(kdc->task->lp_ctx)); if (!samdb) { - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, "Failed to open samdb", reply); } - - DEBUG(3, ("Changing password of %s\\%s (%s)\n", + + DEBUG(3, ("Changing password of %s\\%s (%s)\n", session_info->server_info->domain_name, session_info->server_info->account_name, dom_sid_string(mem_ctx, session_info->security_token->user_sid))); /* User password change */ - status = samdb_set_password_sid(samdb, mem_ctx, + status = samdb_set_password_sid(samdb, mem_ctx, session_info->security_token->user_sid, - password, NULL, NULL, + password, NULL, NULL, true, /* this is a user password change */ &reject_reason, &dominfo); - return kpasswd_make_pwchange_reply(kdc, mem_ctx, - status, + return kpasswd_make_pwchange_reply(kdc, mem_ctx, + status, reject_reason, - dominfo, + dominfo, reply); } static bool kpasswd_process_request(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, + TALLOC_CTX *mem_ctx, struct gensec_security *gensec_security, uint16_t version, - DATA_BLOB *input, + DATA_BLOB *input, DATA_BLOB *reply) { struct auth_session_info *session_info; size_t pw_len; - if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security, + if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security, &session_info))) { - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, "gensec_session_info failed!", reply); @@ -222,16 +222,16 @@ static bool kpasswd_process_request(struct kdc_server *kdc, case KRB5_KPASSWD_VERS_CHANGEPW: { DATA_BLOB password; - if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx), - CH_UTF8, CH_UTF16, - (const char *)input->data, + if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx), + CH_UTF8, CH_UTF16, + (const char *)input->data, input->length, (void **)&password.data, &pw_len, false)) { return false; } password.length = pw_len; - - return kpasswdd_change_password(kdc, mem_ctx, session_info, + + return kpasswdd_change_password(kdc, mem_ctx, session_info, &password, reply); break; } @@ -262,26 +262,26 @@ static bool kpasswd_process_request(struct kdc_server *kdc, ret = decode_ChangePasswdDataMS(input->data, input->length, &chpw, &len); if (ret) { - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_MALFORMED, "failed to decode password change structure", reply); } - - if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx), - CH_UTF8, CH_UTF16, - (const char *)chpw.newpasswd.data, + + if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx), + CH_UTF8, CH_UTF16, + (const char *)chpw.newpasswd.data, chpw.newpasswd.length, (void **)&password.data, &pw_len, false)) { free_ChangePasswdDataMS(&chpw); return false; } - + password.length = pw_len; - - if ((chpw.targname && !chpw.targrealm) + + if ((chpw.targname && !chpw.targrealm) || (!chpw.targname && chpw.targrealm)) { - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_MALFORMED, "Realm and principal must be both present, or neither present", reply); @@ -289,14 +289,14 @@ static bool kpasswd_process_request(struct kdc_server *kdc, if (chpw.targname && chpw.targrealm) { #ifdef SAMBA4_INTERNAL_HEIMDAL if (_krb5_principalname2krb5_principal(kdc->smb_krb5_context->krb5_context, - &principal, *chpw.targname, + &principal, *chpw.targname, *chpw.targrealm) != 0) { free_ChangePasswdDataMS(&chpw); - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_MALFORMED, "failed to extract principal to set", reply); - + } #else /* SAMBA4_INTERNAL_HEIMDAL */ return kpasswdd_make_error_reply(kdc, mem_ctx, @@ -306,54 +306,54 @@ static bool kpasswd_process_request(struct kdc_server *kdc, #endif /* SAMBA4_INTERNAL_HEIMDAL */ } else { free_ChangePasswdDataMS(&chpw); - return kpasswdd_change_password(kdc, mem_ctx, session_info, + return kpasswdd_change_password(kdc, mem_ctx, session_info, &password, reply); } free_ChangePasswdDataMS(&chpw); if (krb5_unparse_name(context, principal, &set_password_on_princ) != 0) { krb5_free_principal(context, principal); - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_MALFORMED, "krb5_unparse_name failed!", reply); } - + krb5_free_principal(context, principal); - + samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info); if (!samdb) { - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, "Unable to open database!", reply); } - DEBUG(3, ("%s\\%s (%s) is changing password of %s\n", + DEBUG(3, ("%s\\%s (%s) is changing password of %s\n", session_info->server_info->domain_name, session_info->server_info->account_name, - dom_sid_string(mem_ctx, session_info->security_token->user_sid), + dom_sid_string(mem_ctx, session_info->security_token->user_sid), set_password_on_princ)); ret = ldb_transaction_start(samdb); if (ret) { status = NT_STATUS_TRANSACTION_ABORTED; - return kpasswd_make_pwchange_reply(kdc, mem_ctx, + return kpasswd_make_pwchange_reply(kdc, mem_ctx, status, SAM_PWD_CHANGE_NO_ERROR, - NULL, + NULL, reply); } - status = crack_user_principal_name(samdb, mem_ctx, - set_password_on_princ, + status = crack_user_principal_name(samdb, mem_ctx, + set_password_on_princ, &set_password_on_dn, NULL); free(set_password_on_princ); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(samdb); - return kpasswd_make_pwchange_reply(kdc, mem_ctx, + return kpasswd_make_pwchange_reply(kdc, mem_ctx, status, SAM_PWD_CHANGE_NO_ERROR, - NULL, + NULL, reply); } @@ -372,7 +372,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc, /* Admin password set */ status = samdb_set_password(samdb, mem_ctx, set_password_on_dn, NULL, - msg, &password, NULL, NULL, + msg, &password, NULL, NULL, false, /* this is not a user password change */ &reject_reason, &dominfo); } @@ -398,17 +398,17 @@ static bool kpasswd_process_request(struct kdc_server *kdc, } else { ldb_transaction_cancel(samdb); } - return kpasswd_make_pwchange_reply(kdc, mem_ctx, + return kpasswd_make_pwchange_reply(kdc, mem_ctx, status, - reject_reason, - dominfo, + reject_reason, + dominfo, reply); } default: - return kpasswdd_make_error_reply(kdc, mem_ctx, + return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_BAD_VERSION, - talloc_asprintf(mem_ctx, - "Protocol version %u not supported", + talloc_asprintf(mem_ctx, + "Protocol version %u not supported", version), reply); } @@ -416,8 +416,8 @@ static bool kpasswd_process_request(struct kdc_server *kdc, } bool kpasswdd_process(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, - DATA_BLOB *input, + TALLOC_CTX *mem_ctx, + DATA_BLOB *input, DATA_BLOB *reply, struct tsocket_address *peer_addr, struct tsocket_address *my_addr, @@ -466,11 +466,11 @@ bool kpasswdd_process(struct kdc_server *kdc, talloc_free(tmp_ctx); return false; } - + krb_priv_len = len - ap_req_len; ap_req = data_blob_const(&input->data[header_len], ap_req_len); krb_priv_req = data_blob_const(&input->data[header_len + ap_req_len], krb_priv_len); - + server_credentials = cli_credentials_init(tmp_ctx); if (!server_credentials) { DEBUG(1, ("Failed to init server credentials\n")); @@ -478,7 +478,7 @@ bool kpasswdd_process(struct kdc_server *kdc, } /* We want the credentials subsystem to use the krb5 context - * we already have, rather than a new context */ + * we already have, rather than a new context */ cli_credentials_set_krb5_context(server_credentials, kdc->smb_krb5_context); cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx); @@ -487,10 +487,10 @@ bool kpasswdd_process(struct kdc_server *kdc, cli_credentials_set_username(server_credentials, "kadmin/changepw", CRED_SPECIFIED); ret = cli_credentials_set_keytab_name(server_credentials, kdc->task->event_ctx, kdc->task->lp_ctx, keytab_name, CRED_SPECIFIED); if (ret != 0) { - ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, + ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, - talloc_asprintf(mem_ctx, - "Failed to obtain server credentials for kadmin/changepw: %s\n", + talloc_asprintf(mem_ctx, + "Failed to obtain server credentials for kadmin/changepw: %s\n", nt_errstr(nt_status)), &krb_priv_rep); ap_rep.length = 0; @@ -500,16 +500,16 @@ bool kpasswdd_process(struct kdc_server *kdc, talloc_free(tmp_ctx); return ret; } - + /* We don't strictly need to call this wrapper, and could call * gensec_server_start directly, as we have no need for NTLM * and we have a PAC, but this ensures that the wrapper can be * safely extended for other helpful things in future */ - nt_status = samba_server_gensec_start(tmp_ctx, kdc->task->event_ctx, + nt_status = samba_server_gensec_start(tmp_ctx, kdc->task->event_ctx, kdc->task->msg_ctx, kdc->task->lp_ctx, server_credentials, - "kpasswd", + "kpasswd", &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); @@ -549,11 +549,11 @@ bool kpasswdd_process(struct kdc_server *kdc, /* Accept the AP-REQ and generate teh AP-REP we need for the reply */ nt_status = gensec_update(gensec_security, tmp_ctx, ap_req, &ap_rep); if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - - ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, + + ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, - talloc_asprintf(mem_ctx, - "gensec_update failed: %s", + talloc_asprintf(mem_ctx, + "gensec_update failed: %s", nt_errstr(nt_status)), &krb_priv_rep); ap_rep.length = 0; @@ -567,10 +567,10 @@ bool kpasswdd_process(struct kdc_server *kdc, /* Extract the data from the KRB-PRIV half of the message */ nt_status = gensec_unwrap(gensec_security, tmp_ctx, &krb_priv_req, &kpasswd_req); if (!NT_STATUS_IS_OK(nt_status)) { - ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, + ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, - talloc_asprintf(mem_ctx, - "gensec_unwrap failed: %s", + talloc_asprintf(mem_ctx, + "gensec_unwrap failed: %s", nt_errstr(nt_status)), &krb_priv_rep); ap_rep.length = 0; @@ -582,10 +582,10 @@ bool kpasswdd_process(struct kdc_server *kdc, } /* Figure out something to do with it (probably changing a password...) */ - ret = kpasswd_process_request(kdc, tmp_ctx, - gensec_security, - version, - &kpasswd_req, &kpasswd_rep); + ret = kpasswd_process_request(kdc, tmp_ctx, + gensec_security, + version, + &kpasswd_req, &kpasswd_rep); if (!ret) { /* Argh! */ return false; @@ -593,13 +593,13 @@ bool kpasswdd_process(struct kdc_server *kdc, /* And wrap up the reply: This ensures that the error message * or success can be verified by the client */ - nt_status = gensec_wrap(gensec_security, tmp_ctx, + nt_status = gensec_wrap(gensec_security, tmp_ctx, &kpasswd_rep, &krb_priv_rep); if (!NT_STATUS_IS_OK(nt_status)) { - ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, + ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, - talloc_asprintf(mem_ctx, - "gensec_wrap failed: %s", + talloc_asprintf(mem_ctx, + "gensec_wrap failed: %s", nt_errstr(nt_status)), &krb_priv_rep); ap_rep.length = 0; @@ -609,7 +609,7 @@ bool kpasswdd_process(struct kdc_server *kdc, talloc_free(tmp_ctx); return ret; } - + reply: *reply = data_blob_talloc(mem_ctx, NULL, krb_priv_rep.length + ap_rep.length + header_len); if (!reply->data) { @@ -619,11 +619,11 @@ reply: RSSVAL(reply->data, 0, reply->length); RSSVAL(reply->data, 2, 1); /* This is a version 1 reply, MS change/set or otherwise */ RSSVAL(reply->data, 4, ap_rep.length); - memcpy(reply->data + header_len, - ap_rep.data, + memcpy(reply->data + header_len, + ap_rep.data, ap_rep.length); - memcpy(reply->data + header_len + ap_rep.length, - krb_priv_rep.data, + memcpy(reply->data + header_len + ap_rep.length, + krb_priv_rep.data, krb_priv_rep.length); talloc_free(tmp_ctx); diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index 3d542d9a94..d921899c61 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -1,21 +1,21 @@ -/* +/* Unix SMB/CIFS implementation. PAC Glue between Samba and the KDC - + Copyright (C) Andrew Bartlett 2005-2009 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 3 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, see . */ @@ -34,22 +34,22 @@ struct krb5_dh_moduli; struct _krb5_krb_auth_data; -static krb5_error_code samba_kdc_plugin_init(krb5_context context, void **ptr) +static krb5_error_code samba_kdc_plugin_init(krb5_context context, void **ptr) { *ptr = NULL; return 0; } -static void samba_kdc_plugin_fini(void *ptr) +static void samba_kdc_plugin_fini(void *ptr) { return; } static krb5_error_code make_pac(krb5_context context, - TALLOC_CTX *mem_ctx, + TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, struct auth_serversupplied_info *server_info, - krb5_pac *pac) + krb5_pac *pac) { union PAC_INFO info; struct netr_SamInfo3 *info3; @@ -105,7 +105,7 @@ static krb5_error_code make_pac(krb5_context context, /* Given the right private pointer from hdb_samba4, get a PAC from the attached ldb messages */ static krb5_error_code samba_kdc_get_pac(void *priv, - krb5_context context, + krb5_context context, struct hdb_entry_ex *client, krb5_pac *pac) { @@ -151,7 +151,7 @@ static krb5_error_code samba_kdc_get_pac(void *priv, static krb5_error_code samba_kdc_reget_pac(void *priv, krb5_context context, const krb5_principal client_principal, - struct hdb_entry_ex *client, + struct hdb_entry_ex *client, struct hdb_entry_ex *server, krb5_pac *pac) { krb5_error_code ret; @@ -163,7 +163,7 @@ static krb5_error_code samba_kdc_reget_pac(void *priv, krb5_context context, struct auth_serversupplied_info *server_info_out; TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_get_pac context"); - + if (!mem_ctx) { return ENOMEM; } @@ -230,8 +230,8 @@ static void samba_kdc_build_edata_reply(TALLOC_CTX *tmp_ctx, krb5_data *e_data, * the account_ok routine in auth/auth_sam.c for consistancy */ -static krb5_error_code samba_kdc_check_client_access(void *priv, - krb5_context context, +static krb5_error_code samba_kdc_check_client_access(void *priv, + krb5_context context, krb5_kdc_configuration *config, hdb_entry_ex *client_ex, const char *client_name, hdb_entry_ex *server_ex, const char *server_name, @@ -253,7 +253,7 @@ static krb5_error_code samba_kdc_check_client_access(void *priv, if (!tmp_ctx) { return ENOMEM; } - + if (addresses) { for (i=0; i < addresses->len; i++) { if (addresses->val->addr_type == KRB5_ADDRESS_NETBIOS) { @@ -276,7 +276,7 @@ static krb5_error_code samba_kdc_check_client_access(void *priv, password_change = (server_ex && server_ex->entry.flags.change_pw); /* we allow all kinds of trusts here */ - nt_status = authsam_account_ok(tmp_ctx, + nt_status = authsam_account_ok(tmp_ctx, p->samdb, MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, p->realm_dn, diff --git a/source4/kdc/pac-glue.h b/source4/kdc/pac-glue.h index 1c14f7fdb6..f838ec353a 100644 --- a/source4/kdc/pac-glue.h +++ b/source4/kdc/pac-glue.h @@ -1,4 +1,4 @@ -/* +/* Unix SMB/CIFS implementation. KDC Server startup @@ -9,12 +9,12 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 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, see . */ -- cgit From 445baf53a9c0c65dafd8558c2b3ec877c3c5fdc8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 23 Dec 2009 09:38:21 +0100 Subject: s4:lib/socket: add helpers functions to convert between socket_address and tsocket_address metze --- source4/lib/socket/config.mk | 2 +- source4/lib/socket/socket.c | 42 ++++++++++++++++++++++++++++++++++++++++++ source4/lib/socket/socket.h | 5 +++++ 3 files changed, 48 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/lib/socket/config.mk b/source4/lib/socket/config.mk index ac515c8f6d..07491e115a 100644 --- a/source4/lib/socket/config.mk +++ b/source4/lib/socket/config.mk @@ -34,7 +34,7 @@ socket_unix_OBJ_FILES = $(libsocketsrcdir)/socket_unix.o ################################################ # Start SUBSYSTEM SOCKET [SUBSYSTEM::samba_socket] -PUBLIC_DEPENDENCIES = LIBTALLOC +PUBLIC_DEPENDENCIES = LIBTALLOC LIBTSOCKET PRIVATE_DEPENDENCIES = SOCKET_WRAPPER LIBCLI_COMPOSITE LIBCLI_RESOLVE # End SUBSYSTEM SOCKET ################################################ diff --git a/source4/lib/socket/socket.c b/source4/lib/socket/socket.c index 8e2f1683f2..23eade7b53 100644 --- a/source4/lib/socket/socket.c +++ b/source4/lib/socket/socket.c @@ -24,6 +24,7 @@ #include "system/filesys.h" #include "system/network.h" #include "param/param.h" +#include "../lib/tsocket/tsocket.h" /* auto-close sockets on free @@ -344,6 +345,47 @@ _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, return sock->ops->fn_get_my_addr(sock, mem_ctx); } +_PUBLIC_ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx, + const struct socket_address *a) +{ + struct tsocket_address *r; + int ret; + + if (a->sockaddr) { + ret = tsocket_address_bsd_from_sockaddr(mem_ctx, + a->sockaddr, + a->sockaddrlen, + &r); + } else { + ret = tsocket_address_inet_from_strings(mem_ctx, + a->family, + a->addr, + a->port, + &r); + } + + if (ret != 0) { + return NULL; + } + + return r; +} + +_PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx, + const struct tsocket_address *a) +{ + ssize_t ret; + struct sockaddr_storage ss; + size_t sslen = sizeof(ss); + + ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen); + if (ret < 0) { + return NULL; + } + + return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret); +} + _PUBLIC_ int socket_get_fd(struct socket_context *sock) { if (!sock->ops->fn_get_fd) { diff --git a/source4/lib/socket/socket.h b/source4/lib/socket/socket.h index 02872457b5..5f29618f14 100644 --- a/source4/lib/socket/socket.h +++ b/source4/lib/socket/socket.h @@ -127,6 +127,7 @@ struct socket_context { }; struct resolve_context; +struct tsocket_address; /* prototypes */ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops, @@ -158,6 +159,10 @@ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, cons char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx); struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx); struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx); +struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx, + const struct socket_address *a); +struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx, + const struct tsocket_address *a); int socket_get_fd(struct socket_context *sock); NTSTATUS socket_dup(struct socket_context *sock); struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx, -- cgit From d3ee0f021b7670404fdcb6171957dbf06ddf0651 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 23 Dec 2009 10:43:05 +0100 Subject: s4:lib/socket: add socket_get_{remote|local}_addr() to get a tsocket_address instead of a socket_address metze --- source4/lib/socket/socket.c | 30 ++++++++++++++++++++++++++++++ source4/lib/socket/socket.h | 2 ++ 2 files changed, 32 insertions(+) (limited to 'source4') diff --git a/source4/lib/socket/socket.c b/source4/lib/socket/socket.c index 23eade7b53..30db03fd97 100644 --- a/source4/lib/socket/socket.c +++ b/source4/lib/socket/socket.c @@ -386,6 +386,36 @@ _PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *me return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret); } +_PUBLIC_ struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + struct socket_address *a; + struct tsocket_address *r; + + a = socket_get_peer_addr(sock, mem_ctx); + if (a == NULL) { + return NULL; + } + + r = socket_address_to_tsocket_address(mem_ctx, a); + talloc_free(a); + return r; +} + +_PUBLIC_ struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + struct socket_address *a; + struct tsocket_address *r; + + a = socket_get_my_addr(sock, mem_ctx); + if (a == NULL) { + return NULL; + } + + r = socket_address_to_tsocket_address(mem_ctx, a); + talloc_free(a); + return r; +} + _PUBLIC_ int socket_get_fd(struct socket_context *sock) { if (!sock->ops->fn_get_fd) { diff --git a/source4/lib/socket/socket.h b/source4/lib/socket/socket.h index 5f29618f14..8f8922bcea 100644 --- a/source4/lib/socket/socket.h +++ b/source4/lib/socket/socket.h @@ -163,6 +163,8 @@ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx, const struct socket_address *a); struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx, const struct tsocket_address *a); +struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx); +struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx); int socket_get_fd(struct socket_context *sock); NTSTATUS socket_dup(struct socket_context *sock); struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx, -- cgit From 4e2da423de260468f0457410b0556088f00420d4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 23 Dec 2009 10:19:43 +0100 Subject: s4:smb_server: fix mixing socket_address and tsocket_address metze --- source4/smb_server/smb/sesssetup.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'source4') diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c index 37f69abc12..8cd2edcee3 100644 --- a/source4/smb_server/smb/sesssetup.c +++ b/source4/smb_server/smb/sesssetup.c @@ -29,6 +29,7 @@ #include "smb_server/smb_server.h" #include "smbd/service_stream.h" #include "param/param.h" +#include "../lib/tsocket/tsocket.h" /* setup the OS, Lanman and domain portions of a session setup reply @@ -100,7 +101,7 @@ failed: static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess) { struct auth_usersupplied_info *user_info = NULL; - struct socket_address *remote_address; + struct tsocket_address *remote_address; const char *remote_machine = NULL; sess->old.out.vuid = 0; @@ -119,11 +120,12 @@ static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess) remote_machine = req->smb_conn->negotiate.calling_name->name; } - remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req); + remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req); if (!remote_address) goto nomem; if (!remote_machine) { - remote_machine = remote_address->addr; + remote_machine = tsocket_address_inet_addr_string(remote_address, req); + if (!remote_machine) goto nomem; } user_info = talloc(req, struct auth_usersupplied_info); @@ -206,7 +208,7 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess) NTSTATUS status; struct auth_context *auth_context; struct auth_usersupplied_info *user_info = NULL; - struct socket_address *remote_address; + struct tsocket_address *remote_address; const char *remote_machine = NULL; sess->nt1.out.vuid = 0; @@ -245,11 +247,12 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess) remote_machine = req->smb_conn->negotiate.calling_name->name; } - remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req); + remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req); if (!remote_address) goto nomem; if (!remote_machine) { - remote_machine = remote_address->addr; + remote_machine = tsocket_address_inet_addr_string(remote_address, req); + if (!remote_machine) goto nomem; } user_info = talloc(req, struct auth_usersupplied_info); -- cgit From 500f55ca92efe0235758b131a33bc1645c0545ac Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 23 Dec 2009 11:48:06 +0100 Subject: s4:smbd: hold tsocket_addresses on the stream_connection metze --- source4/smbd/config.mk | 2 +- source4/smbd/service_stream.c | 32 +++++++++++++++++++++++--------- source4/smbd/service_stream.h | 3 +++ 3 files changed, 27 insertions(+), 10 deletions(-) (limited to 'source4') diff --git a/source4/smbd/config.mk b/source4/smbd/config.mk index b85beb0bc0..a77a18602f 100644 --- a/source4/smbd/config.mk +++ b/source4/smbd/config.mk @@ -4,7 +4,7 @@ PRIVATE_DEPENDENCIES = \ LIBTEVENT MESSAGING samba_socket \ NDR_NAMED_PIPE_AUTH NAMED_PIPE_AUTH_TSTREAM \ - HEIMDAL_GSSAPI CREDENTIALS + HEIMDAL_GSSAPI CREDENTIALS LIBTSOCKET service_OBJ_FILES = $(addprefix $(smbdsrcdir)/, \ service.o \ diff --git a/source4/smbd/service_stream.c b/source4/smbd/service_stream.c index ab35eb04bf..2d8b9559f4 100644 --- a/source4/smbd/service_stream.c +++ b/source4/smbd/service_stream.c @@ -26,6 +26,7 @@ #include "lib/messaging/irpc.h" #include "cluster/cluster.h" #include "param/param.h" +#include "../lib/tsocket/tsocket.h" /* the range of ports to try for dcerpc over tcp endpoints */ #define SERVER_TCP_LOW_PORT 1024 @@ -164,7 +165,6 @@ static void stream_new_connection(struct tevent_context *ev, { struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket); struct stream_connection *srv_conn; - struct socket_address *c, *s; srv_conn = talloc_zero(ev, struct stream_connection); if (!srv_conn) { @@ -205,20 +205,34 @@ static void stream_new_connection(struct tevent_context *ev, return; } - c = socket_get_peer_addr(sock, ev); - s = socket_get_my_addr(sock, ev); - if (s && c) { + srv_conn->remote_address = socket_get_remote_addr(srv_conn->socket, srv_conn); + if (!srv_conn->remote_address) { + stream_terminate_connection(srv_conn, "socket_get_remote_addr() failed"); + return; + } + + srv_conn->local_address = socket_get_local_addr(srv_conn->socket, srv_conn); + if (!srv_conn->local_address) { + stream_terminate_connection(srv_conn, "socket_get_local_addr() failed"); + return; + } + + { + TALLOC_CTX *tmp_ctx; const char *title; - title = talloc_asprintf(s, "conn[%s] c[%s:%u] s[%s:%u] server_id[%s]", + + tmp_ctx = talloc_new(srv_conn); + + title = talloc_asprintf(tmp_ctx, "conn[%s] c[%s] s[%s] server_id[%s]", stream_socket->ops->name, - c->addr, c->port, s->addr, s->port, - cluster_id_string(s, server_id)); + tsocket_address_string(srv_conn->remote_address, tmp_ctx), + tsocket_address_string(srv_conn->local_address, tmp_ctx), + cluster_id_string(tmp_ctx, server_id)); if (title) { stream_connection_set_title(srv_conn, title); } + talloc_free(tmp_ctx); } - talloc_free(c); - talloc_free(s); /* we're now ready to start receiving events on this stream */ TEVENT_FD_READABLE(srv_conn->event.fde); diff --git a/source4/smbd/service_stream.h b/source4/smbd/service_stream.h index 5d577d4dd8..685502a8ba 100644 --- a/source4/smbd/service_stream.h +++ b/source4/smbd/service_stream.h @@ -50,6 +50,9 @@ struct stream_connection { struct messaging_context *msg_ctx; struct loadparm_context *lp_ctx; + struct tsocket_address *local_address; + struct tsocket_address *remote_address; + /* * this transport layer session info, normally NULL * which means the same as an anonymous session info -- cgit From 5126b52810628bb8d37a7d7768beb18771c4330f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 23 Dec 2009 11:16:32 +0100 Subject: s4:kdc: use the remote and local address from the stream_connection struct metze --- source4/kdc/kdc.c | 43 ++----------------------------------------- 1 file changed, 2 insertions(+), 41 deletions(-) (limited to 'source4') diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c index b2921842e7..93f1c7d6ec 100644 --- a/source4/kdc/kdc.c +++ b/source4/kdc/kdc.c @@ -73,9 +73,6 @@ struct kdc_tcp_connection { /* the kdc_server the connection belongs to */ struct kdc_socket *kdc_socket; - struct tsocket_address *local_address; - struct tsocket_address *remote_address; - struct packet_context *packet; }; @@ -104,8 +101,8 @@ static NTSTATUS kdc_tcp_recv(void *private_data, DATA_BLOB blob) tmp_ctx, &input, &reply, - kdcconn->remote_address, - kdcconn->local_address, + kdcconn->conn->remote_address, + kdcconn->conn->local_address, 0 /* Not datagram */); if (!ret) { talloc_free(tmp_ctx); @@ -224,9 +221,6 @@ static void kdc_tcp_accept(struct stream_connection *conn) { struct kdc_socket *kdc_socket = talloc_get_type(conn->private_data, struct kdc_socket); struct kdc_tcp_connection *kdcconn; - struct socket_address *src_addr; - struct socket_address *my_addr; - int ret; kdcconn = talloc_zero(conn, struct kdc_tcp_connection); if (!kdcconn) { @@ -237,39 +231,6 @@ static void kdc_tcp_accept(struct stream_connection *conn) kdcconn->kdc_socket = kdc_socket; conn->private_data = kdcconn; - src_addr = socket_get_peer_addr(kdcconn->conn->socket, kdcconn); - if (!src_addr) { - kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); - return; - } - - my_addr = socket_get_my_addr(kdcconn->conn->socket, kdcconn); - if (!my_addr) { - kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); - return; - } - - ret = tsocket_address_bsd_from_sockaddr(kdcconn, - src_addr->sockaddr, - src_addr->sockaddrlen, - &kdcconn->remote_address); - if (ret < 0) { - kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); - return; - } - - ret = tsocket_address_bsd_from_sockaddr(kdcconn, - my_addr->sockaddr, - my_addr->sockaddrlen, - &kdcconn->local_address); - if (ret < 0) { - kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); - return; - } - - TALLOC_FREE(src_addr); - TALLOC_FREE(my_addr); - kdcconn->packet = packet_init(kdcconn); if (kdcconn->packet == NULL) { kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); -- cgit From 577857d351df3d7b40db4d69afb3d67ee4960fb2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 22 Dec 2009 16:24:44 +0100 Subject: s4:gensec: change gensec_update_send/recv to tevent_req metze --- source4/auth/gensec/config.mk | 2 +- source4/auth/gensec/gensec.c | 117 +++++++++++++++++++++++------------- source4/auth/gensec/gensec.h | 22 ++----- source4/smb_server/smb/sesssetup.c | 20 ++++-- source4/smb_server/smb2/sesssetup.c | 17 ++++-- 5 files changed, 110 insertions(+), 68 deletions(-) (limited to 'source4') diff --git a/source4/auth/gensec/config.mk b/source4/auth/gensec/config.mk index f7cbd5b197..947a91e852 100644 --- a/source4/auth/gensec/config.mk +++ b/source4/auth/gensec/config.mk @@ -2,7 +2,7 @@ # Start SUBSYSTEM gensec [LIBRARY::gensec] PUBLIC_DEPENDENCIES = \ - CREDENTIALS LIBSAMBA-UTIL LIBCRYPTO ASN1_UTIL samba_socket LIBPACKET LIBTSOCKET + CREDENTIALS LIBSAMBA-UTIL LIBCRYPTO ASN1_UTIL samba_socket LIBPACKET LIBTSOCKET UTIL_TEVENT # End SUBSYSTEM gensec ################################# diff --git a/source4/auth/gensec/gensec.c b/source4/auth/gensec/gensec.c index ecd0778ee6..3de0e1c935 100644 --- a/source4/auth/gensec/gensec.c +++ b/source4/auth/gensec/gensec.c @@ -25,6 +25,7 @@ #include "lib/events/events.h" #include "lib/socket/socket.h" #include "lib/tsocket/tsocket.h" +#include "../lib/util/tevent_ntstatus.h" #include "librpc/rpc/dcerpc.h" #include "auth/credentials/credentials.h" #include "auth/gensec/gensec.h" @@ -982,71 +983,105 @@ _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_ return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out); } -static void gensec_update_async_timed_handler(struct tevent_context *ev, struct tevent_timer *te, - struct timeval t, void *ptr) -{ - struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request); - req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out); - req->callback.fn(req, req->callback.private_data); -} +struct gensec_update_state { + struct tevent_immediate *im; + struct gensec_security *gensec_security; + DATA_BLOB in; + DATA_BLOB out; +}; +static void gensec_update_async_trigger(struct tevent_context *ctx, + struct tevent_immediate *im, + void *private_data); /** * Next state function for the GENSEC state machine async version - * + * + * @param mem_ctx The memory context for the request + * @param ev The event context for the request * @param gensec_security GENSEC State * @param in The request, as a DATA_BLOB - * @param callback The function that will be called when the operation is - * finished, it should return gensec_update_recv() to get output - * @param private_data A private pointer that will be passed to the callback function + * + * @return The request handle or NULL on no memory failure */ -_PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in, - void (*callback)(struct gensec_update_request *req, void *private_data), - void *private_data) +_PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct gensec_security *gensec_security, + const DATA_BLOB in) +{ + struct tevent_req *req; + struct gensec_update_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, + struct gensec_update_state); + if (req == NULL) { + return NULL; + } + + state->gensec_security = gensec_security; + state->in = in; + state->out = data_blob(NULL, 0); + state->im = tevent_create_immediate(state); + if (tevent_req_nomem(state->im, req)) { + return tevent_req_post(req, ev); + } + + tevent_schedule_immediate(state->im, ev, + gensec_update_async_trigger, + req); + + return req; +} + +static void gensec_update_async_trigger(struct tevent_context *ctx, + struct tevent_immediate *im, + void *private_data) { - struct gensec_update_request *req = NULL; - struct tevent_timer *te = NULL; - - req = talloc(gensec_security, struct gensec_update_request); - if (!req) goto failed; - req->gensec_security = gensec_security; - req->in = in; - req->out = data_blob(NULL, 0); - req->callback.fn = callback; - req->callback.private_data = private_data; - - te = event_add_timed(gensec_security->event_ctx, req, - timeval_zero(), - gensec_update_async_timed_handler, req); - if (!te) goto failed; - - return; - -failed: - talloc_free(req); - callback(NULL, private_data); + struct tevent_req *req = + talloc_get_type_abort(private_data, struct tevent_req); + struct gensec_update_state *state = + tevent_req_data(req, struct gensec_update_state); + NTSTATUS status; + + status = gensec_update(state->gensec_security, state, + state->in, &state->out); + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); } /** * Next state function for the GENSEC state machine * - * @param req GENSEC update request state + * @param req request state * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, * or NT_STATUS_OK if the user is authenticated. */ -_PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out) +_PUBLIC_ NTSTATUS gensec_update_recv(struct tevent_req *req, + TALLOC_CTX *out_mem_ctx, + DATA_BLOB *out) { + struct gensec_update_state *state = + tevent_req_data(req, struct gensec_update_state); NTSTATUS status; - NT_STATUS_HAVE_NO_MEMORY(req); + if (tevent_req_is_nterror(req, &status)) { + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_received(req); + return status; + } + } else { + status = NT_STATUS_OK; + } - *out = req->out; + *out = state->out; talloc_steal(out_mem_ctx, out->data); - status = req->status; - talloc_free(req); + tevent_req_received(req); return status; } diff --git a/source4/auth/gensec/gensec.h b/source4/auth/gensec/gensec.h index 2ea2402064..232f1a4500 100644 --- a/source4/auth/gensec/gensec.h +++ b/source4/auth/gensec/gensec.h @@ -69,18 +69,7 @@ struct auth_session_info; struct cli_credentials; struct gensec_settings; struct tevent_context; - -struct gensec_update_request { - struct gensec_security *gensec_security; - void *private_data; - DATA_BLOB in; - DATA_BLOB out; - NTSTATUS status; - struct { - void (*fn)(struct gensec_update_request *req, void *private_data); - void *private_data; - } callback; -}; +struct tevent_req; struct gensec_settings { struct loadparm_context *lp_ctx; @@ -231,10 +220,11 @@ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security, const char **sasl_names); NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, const DATA_BLOB in, DATA_BLOB *out); -void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in, - void (*callback)(struct gensec_update_request *req, void *private_data), - void *private_data); -NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out); +struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct gensec_security *gensec_security, + const DATA_BLOB in); +NTSTATUS gensec_update_recv(struct tevent_req *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out); void gensec_want_feature(struct gensec_security *gensec_security, uint32_t feature); bool gensec_have_feature(struct gensec_security *gensec_security, diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c index 8cd2edcee3..e415a47699 100644 --- a/source4/smb_server/smb/sesssetup.c +++ b/source4/smb_server/smb/sesssetup.c @@ -23,6 +23,7 @@ */ #include "includes.h" +#include #include "version.h" #include "auth/gensec/gensec.h" #include "auth/auth.h" @@ -289,9 +290,9 @@ struct sesssetup_spnego_state { struct smbsrv_session *smb_sess; }; -static void sesssetup_spnego_send(struct gensec_update_request *greq, void *private_data) +static void sesssetup_spnego_send(struct tevent_req *subreq) { - struct sesssetup_spnego_state *s = talloc_get_type(private_data, + struct sesssetup_spnego_state *s = tevent_req_callback_data(subreq, struct sesssetup_spnego_state); struct smbsrv_request *req = s->req; union smb_sesssetup *sess = s->sess; @@ -301,7 +302,8 @@ static void sesssetup_spnego_send(struct gensec_update_request *greq, void *priv NTSTATUS skey_status; DATA_BLOB session_key; - status = gensec_update_recv(greq, req, &sess->spnego.out.secblob); + status = gensec_update_recv(subreq, req, &sess->spnego.out.secblob); + TALLOC_FREE(subreq); if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { goto done; } else if (!NT_STATUS_IS_OK(status)) { @@ -343,6 +345,7 @@ static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *se struct smbsrv_session *smb_sess = NULL; struct sesssetup_spnego_state *s = NULL; uint16_t vuid; + struct tevent_req *subreq; sess->spnego.out.vuid = 0; sess->spnego.out.action = 0; @@ -410,8 +413,15 @@ static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *se s->sess = sess; s->smb_sess = smb_sess; - gensec_update_send(smb_sess->gensec_ctx, sess->spnego.in.secblob, - sesssetup_spnego_send, s); + subreq = gensec_update_send(s, + req->smb_conn->connection->event.ctx, + smb_sess->gensec_ctx, + sess->spnego.in.secblob); + if (!subreq) { + goto nomem; + } + tevent_req_set_callback(subreq, sesssetup_spnego_send, s); + return; nomem: diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c index 58090305a0..9b601d17c0 100644 --- a/source4/smb_server/smb2/sesssetup.c +++ b/source4/smb_server/smb2/sesssetup.c @@ -19,6 +19,7 @@ */ #include "includes.h" +#include #include "auth/gensec/gensec.h" #include "auth/auth.h" #include "libcli/smb2/smb2.h" @@ -57,9 +58,9 @@ struct smb2srv_sesssetup_callback_ctx { struct smbsrv_session *smb_sess; }; -static void smb2srv_sesssetup_callback(struct gensec_update_request *greq, void *private_data) +static void smb2srv_sesssetup_callback(struct tevent_req *subreq) { - struct smb2srv_sesssetup_callback_ctx *ctx = talloc_get_type(private_data, + struct smb2srv_sesssetup_callback_ctx *ctx = tevent_req_callback_data(subreq, struct smb2srv_sesssetup_callback_ctx); struct smb2srv_request *req = ctx->req; union smb_sesssetup *io = ctx->io; @@ -67,7 +68,8 @@ static void smb2srv_sesssetup_callback(struct gensec_update_request *greq, void struct auth_session_info *session_info = NULL; NTSTATUS status; - status = gensec_update_recv(greq, req, &io->smb2.out.secblob); + status = gensec_update_recv(subreq, req, &io->smb2.out.secblob); + TALLOC_FREE(subreq); if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { goto done; } else if (!NT_STATUS_IS_OK(status)) { @@ -108,6 +110,7 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses struct smb2srv_sesssetup_callback_ctx *callback_ctx; struct smbsrv_session *smb_sess = NULL; uint64_t vuid; + struct tevent_req *subreq; io->smb2.out.session_flags = 0; io->smb2.out.uid = 0; @@ -174,8 +177,12 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses callback_ctx->io = io; callback_ctx->smb_sess = smb_sess; - gensec_update_send(smb_sess->gensec_ctx, io->smb2.in.secblob, - smb2srv_sesssetup_callback, callback_ctx); + subreq = gensec_update_send(callback_ctx, + req->smb_conn->connection->event.ctx, + smb_sess->gensec_ctx, + io->smb2.in.secblob); + if (!subreq) goto nomem; + tevent_req_set_callback(subreq, smb2srv_sesssetup_callback, callback_ctx); /* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client. This is deliberate as windows does not set it even when it does -- cgit From 078482ad0efc9c4902601080f146853a1a3494fe Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 23 Dec 2009 09:09:37 +0100 Subject: s4:auth: change auth_check_password_send/recv to tevent_req metze --- source4/auth/auth.h | 12 +- source4/auth/ntlm/auth.c | 242 +++++++++++++++++++++---------------- source4/auth/ntlm/config.mk | 2 +- source4/smb_server/smb/sesssetup.c | 39 ++++-- 4 files changed, 169 insertions(+), 126 deletions(-) (limited to 'source4') diff --git a/source4/auth/auth.h b/source4/auth/auth.h index c625c87f39..28b955a516 100644 --- a/source4/auth/auth.h +++ b/source4/auth/auth.h @@ -275,14 +275,16 @@ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx, const char *nt4_username, const char *password, struct auth_session_info **session_info); -NTSTATUS auth_check_password_recv(struct auth_check_password_request *req, + +struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct auth_context *auth_ctx, + const struct auth_usersupplied_info *user_info); +NTSTATUS auth_check_password_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct auth_serversupplied_info **server_info); -void auth_check_password_send(struct auth_context *auth_ctx, - const struct auth_usersupplied_info *user_info, - void (*callback)(struct auth_check_password_request *req, void *private_data), - void *private_data); + NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by); NTSTATUS samba_server_gensec_start(TALLOC_CTX *mem_ctx, diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c index d0c8ed3a68..fafaf9cbb2 100644 --- a/source4/auth/ntlm/auth.c +++ b/source4/auth/ntlm/auth.c @@ -19,10 +19,11 @@ */ #include "includes.h" +#include +#include "../lib/util/tevent_ntstatus.h" #include "../lib/util/dlinklist.h" #include "auth/auth.h" #include "auth/ntlm/auth_proto.h" -#include "lib/events/events.h" #include "param/param.h" /*************************************************************************** @@ -124,22 +125,6 @@ _PUBLIC_ NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } -struct auth_check_password_sync_state { - bool finished; - NTSTATUS status; - struct auth_serversupplied_info *server_info; -}; - -static void auth_check_password_sync_callback(struct auth_check_password_request *req, - void *private_data) -{ - struct auth_check_password_sync_state *s = talloc_get_type(private_data, - struct auth_check_password_sync_state); - - s->finished = true; - s->status = auth_check_password_recv(req, s, &s->server_info); -} - /** * Check a user's Plaintext, LM or NTLM password. * (sync version) @@ -172,48 +157,43 @@ _PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx, const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) { - struct auth_check_password_sync_state *sync_state; + struct tevent_req *subreq; + struct tevent_context *ev; + bool ok; NTSTATUS status; - sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state); - NT_STATUS_HAVE_NO_MEMORY(sync_state); + /*TODO: create a new event context here! */ + ev = auth_ctx->event_ctx; - auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state); - - while (!sync_state->finished) { - event_loop_once(auth_ctx->event_ctx); + subreq = auth_check_password_send(mem_ctx, + ev, + auth_ctx, + user_info); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY; } - status = sync_state->status; - - if (NT_STATUS_IS_OK(status)) { - *server_info = talloc_steal(mem_ctx, sync_state->server_info); + ok = tevent_req_poll(subreq, ev); + if (!ok) { + return NT_STATUS_INTERNAL_ERROR; } - talloc_free(sync_state); + status = auth_check_password_recv(subreq, mem_ctx, server_info); + TALLOC_FREE(subreq); + return status; } -struct auth_check_password_request { +struct auth_check_password_state { struct auth_context *auth_ctx; const struct auth_usersupplied_info *user_info; struct auth_serversupplied_info *server_info; struct auth_method_context *method; - NTSTATUS status; - struct { - void (*fn)(struct auth_check_password_request *req, void *private_data); - void *private_data; - } callback; }; -static void auth_check_password_async_timed_handler(struct tevent_context *ev, struct tevent_timer *te, - struct timeval t, void *ptr) -{ - struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request); - req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info); - req->callback.fn(req, req->callback.private_data); -} - +static void auth_check_password_async_trigger(struct tevent_context *ev, + struct tevent_immediate *im, + void *private_data); /** * Check a user's Plaintext, LM or NTLM password. * async send hook @@ -225,6 +205,10 @@ static void auth_check_password_async_timed_handler(struct tevent_context *ev, s * struct. When the return is other than NT_STATUS_OK the contents * of that structure is undefined. * + * @param mem_ctx The memory context the request should operate on + * + * @param ev The tevent context the request should operate on + * * @param auth_ctx Supplies the challenges and some other data. * Must be created with make_auth_context(), and the challenges should be * filled in, either at creation or by calling the challenge geneation @@ -232,93 +216,131 @@ static void auth_check_password_async_timed_handler(struct tevent_context *ev, s * * @param user_info Contains the user supplied components, including the passwords. * - * @param callback A callback function which will be called when the operation is finished. - * The callback function needs to call auth_check_password_recv() to get the return values - * - * @param private_data A private pointer which will ba passed to the callback function + * @return The request handle or NULL on no memory error. * **/ -_PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx, - const struct auth_usersupplied_info *user_info, - void (*callback)(struct auth_check_password_request *req, void *private_data), - void *private_data) +_PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct auth_context *auth_ctx, + const struct auth_usersupplied_info *user_info) { + struct tevent_req *req; + struct auth_check_password_state *state; /* if all the modules say 'not for me' this is reasonable */ NTSTATUS nt_status; struct auth_method_context *method; uint8_t chal[8]; struct auth_usersupplied_info *user_info_tmp; - struct auth_check_password_request *req = NULL; + struct tevent_immediate *im; - DEBUG(3, ("auth_check_password_send: Checking password for unmapped user [%s]\\[%s]@[%s]\n", - user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); + DEBUG(3,("auth_check_password_send: " + "Checking password for unmapped user [%s]\\[%s]@[%s]\n", + user_info->client.domain_name, user_info->client.account_name, + user_info->workstation_name)); - req = talloc_zero(auth_ctx, struct auth_check_password_request); - if (!req) { - callback(NULL, private_data); - return; + req = tevent_req_create(mem_ctx, &state, + struct auth_check_password_state); + if (req == NULL) { + return NULL; } - req->auth_ctx = auth_ctx; - req->user_info = user_info; - req->callback.fn = callback; - req->callback.private_data = private_data; + + state->auth_ctx = auth_ctx; + state->user_info = user_info; + state->method = NULL; if (!user_info->mapped_state) { - nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp); - if (!NT_STATUS_IS_OK(nt_status)) goto failed; + nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), + user_info, &user_info_tmp); + if (tevent_req_nterror(req, nt_status)) { + return tevent_req_post(req, ev); + } user_info = user_info_tmp; - req->user_info = user_info_tmp; + state->user_info = user_info_tmp; } - DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n", - user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name)); + DEBUGADD(3,("auth_check_password_send: " + "mapped user is: [%s]\\[%s]@[%s]\n", + user_info->mapped.domain_name, + user_info->mapped.account_name, + user_info->workstation_name)); nt_status = auth_get_challenge(auth_ctx, chal); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n", - (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status))); - goto failed; + if (tevent_req_nterror(req, nt_status)) { + DEBUG(0,("auth_check_password_send: " + "Invalid challenge (length %u) stored for " + "this auth context set_by %s - cannot continue: %s\n", + (unsigned)auth_ctx->challenge.data.length, + auth_ctx->challenge.set_by, + nt_errstr(nt_status))); + return tevent_req_post(req, ev); } if (auth_ctx->challenge.set_by) { - DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n", - auth_ctx->challenge.set_by)); + DEBUG(10,("auth_check_password_send: " + "auth_context challenge created by %s\n", + auth_ctx->challenge.set_by)); } DEBUG(10, ("auth_check_password_send: challenge is: \n")); - dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length); + dump_data(5, auth_ctx->challenge.data.data, + auth_ctx->challenge.data.length); + + im = tevent_create_immediate(state); + if (tevent_req_nomem(im, req)) { + return tevent_req_post(req, ev); + } - nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */ for (method = auth_ctx->methods; method; method = method->next) { NTSTATUS result; - struct tevent_timer *te = NULL; /* check if the module wants to chek the password */ result = method->ops->want_check(method, req, user_info); if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) { - DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name)); + DEBUG(11,("auth_check_password_send: " + "%s had nothing to say\n", + method->ops->name)); continue; } - nt_status = result; - req->method = method; + state->method = method; - if (!NT_STATUS_IS_OK(nt_status)) break; - - te = event_add_timed(auth_ctx->event_ctx, req, - timeval_zero(), - auth_check_password_async_timed_handler, req); - if (!te) { - nt_status = NT_STATUS_NO_MEMORY; - goto failed; + if (tevent_req_nterror(req, result)) { + return tevent_req_post(req, ev); } + + tevent_schedule_immediate(im, + auth_ctx->event_ctx, + auth_check_password_async_trigger, + req); + + return req; + } + + /* If all the modules say 'not for me', then this is reasonable */ + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); +} + +static void auth_check_password_async_trigger(struct tevent_context *ev, + struct tevent_immediate *im, + void *private_data) +{ + struct tevent_req *req = + talloc_get_type_abort(private_data, struct tevent_req); + struct auth_check_password_state *state = + tevent_req_data(req, struct auth_check_password_state); + NTSTATUS status; + + status = state->method->ops->check_password(state->method, + state, + state->user_info, + &state->server_info); + if (tevent_req_nterror(req, status)) { return; } -failed: - req->status = nt_status; - req->callback.fn(req, req->callback.private_data); + tevent_req_done(req); } /** @@ -330,7 +352,7 @@ failed: * of that structure is undefined. * * - * @param req The async auth_check_password state, passes to the callers callback function + * @param req The async request state * * @param mem_ctx The parent memory context for the server_info structure * @@ -341,30 +363,36 @@ failed: * **/ -_PUBLIC_ NTSTATUS auth_check_password_recv(struct auth_check_password_request *req, +_PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct auth_serversupplied_info **server_info) { + struct auth_check_password_state *state = + tevent_req_data(req, struct auth_check_password_state); NTSTATUS status; - NT_STATUS_HAVE_NO_MEMORY(req); + if (tevent_req_is_nterror(req, &status)) { + DEBUG(2,("auth_check_password_recv: " + "%s authentication for user [%s\\%s]" + "FAILED with error %s\n", + (state->method ? state->method->ops->name : "NO_METHOD"), + state->user_info->mapped.domain_name, + state->user_info->mapped.account_name, + nt_errstr(status))); + tevent_req_received(req); + return status; + } - if (NT_STATUS_IS_OK(req->status)) { - DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n", - req->method->ops->name, req->server_info->domain_name, req->server_info->account_name)); + DEBUG(5,("auth_check_password_recv: " + "%s authentication for user [%s\\%s] succeeded\n", + state->method->ops->name, + state->server_info->domain_name, + state->server_info->account_name)); - *server_info = talloc_steal(mem_ctx, req->server_info); - } else { - DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n", - (req->method ? req->method->ops->name : "NO_METHOD"), - req->user_info->mapped.domain_name, - req->user_info->mapped.account_name, - nt_errstr(req->status))); - } + *server_info = talloc_move(mem_ctx, &state->server_info); - status = req->status; - talloc_free(req); - return status; + tevent_req_received(req); + return NT_STATUS_OK; } /*************************************************************************** diff --git a/source4/auth/ntlm/config.mk b/source4/auth/ntlm/config.mk index 82738529cf..6c75ae842d 100644 --- a/source4/auth/ntlm/config.mk +++ b/source4/auth/ntlm/config.mk @@ -71,7 +71,7 @@ PAM_ERRORS_OBJ_FILES = $(addprefix $(authsrcdir)/ntlm/, pam_errors.o) INIT_FUNCTION = server_service_auth_init SUBSYSTEM = service OUTPUT_TYPE = MERGED_OBJ -PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSECURITY SAMDB CREDENTIALS +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSECURITY SAMDB CREDENTIALS UTIL_TEVENT auth_OBJ_FILES = $(addprefix $(authsrcdir)/ntlm/, auth.o auth_util.o auth_simple.o) $(eval $(call proto_header_template,$(authsrcdir)/ntlm/auth_proto.h,$(auth_OBJ_FILES:.o=.c))) diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c index e415a47699..aecd49fb0b 100644 --- a/source4/smb_server/smb/sesssetup.c +++ b/source4/smb_server/smb/sesssetup.c @@ -56,17 +56,18 @@ static void smbsrv_sesssetup_backend_send(struct smbsrv_request *req, smbsrv_reply_sesssetup_send(req, sess, status); } -static void sesssetup_old_send(struct auth_check_password_request *areq, - void *private_data) +static void sesssetup_old_send(struct tevent_req *subreq) { - struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request); + struct smbsrv_request *req = + tevent_req_callback_data(subreq, struct smbsrv_request); union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup); struct auth_serversupplied_info *server_info = NULL; struct auth_session_info *session_info; struct smbsrv_session *smb_sess; NTSTATUS status; - status = auth_check_password_recv(areq, req, &server_info); + status = auth_check_password_recv(subreq, req, &server_info); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) goto failed; /* This references server_info into session_info */ @@ -104,6 +105,7 @@ static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess) struct auth_usersupplied_info *user_info = NULL; struct tsocket_address *remote_address; const char *remote_machine = NULL; + struct tevent_req *subreq; sess->old.out.vuid = 0; sess->old.out.action = 0; @@ -145,25 +147,30 @@ static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess) user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data); user_info->password.response.nt = data_blob(NULL, 0); - auth_check_password_send(req->smb_conn->negotiate.auth_context, user_info, - sesssetup_old_send, req); + subreq = auth_check_password_send(req, + req->smb_conn->connection->event.ctx, + req->smb_conn->negotiate.auth_context, + user_info); + if (!subreq) goto nomem; + tevent_req_set_callback(subreq, sesssetup_old_send, req); return; nomem: smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY); } -static void sesssetup_nt1_send(struct auth_check_password_request *areq, - void *private_data) +static void sesssetup_nt1_send(struct tevent_req *subreq) { - struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request); + struct smbsrv_request *req = + tevent_req_callback_data(subreq, struct smbsrv_request); union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup); struct auth_serversupplied_info *server_info = NULL; struct auth_session_info *session_info; struct smbsrv_session *smb_sess; NTSTATUS status; - status = auth_check_password_recv(areq, req, &server_info); + status = auth_check_password_recv(subreq, req, &server_info); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) goto failed; /* This references server_info into session_info */ @@ -211,7 +218,8 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess) struct auth_usersupplied_info *user_info = NULL; struct tsocket_address *remote_address; const char *remote_machine = NULL; - + struct tevent_req *subreq; + sess->nt1.out.vuid = 0; sess->nt1.out.action = 0; @@ -273,8 +281,13 @@ static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess) user_info->password.response.nt = sess->nt1.in.password2; user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data); - auth_check_password_send(auth_context, user_info, - sesssetup_nt1_send, req); + subreq = auth_check_password_send(req, + req->smb_conn->connection->event.ctx, + auth_context, + user_info); + if (!subreq) goto nomem; + tevent_req_set_callback(subreq, sesssetup_nt1_send, req); + return; nomem: -- cgit From f03e88fa4bc1101ca9031d697f33e36effb669fd Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Thu, 24 Dec 2009 04:08:12 +0200 Subject: s4-net: Fix 'talloc_free with references ...' error Signed-off-by: Jelmer Vernooij --- source4/libnet/libnet_passwd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c index cb09e3041e..8195347b83 100644 --- a/source4/libnet/libnet_passwd.c +++ b/source4/libnet/libnet_passwd.c @@ -109,11 +109,11 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT nt_errstr(status)); r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser3 for '%s\\%s' failed: %s", - r->samr.in.domain_name, r->samr.in.account_name, + r->samr.in.domain_name, r->samr.in.account_name, nt_errstr(status)); } goto disconnect; - } + } /* prepare samr_ChangePasswordUser2 */ encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE); @@ -216,7 +216,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT #endif disconnect: /* close connection */ - talloc_free(c.out.dcerpc_pipe); + talloc_unlink(ctx, c.out.dcerpc_pipe); return status; } @@ -627,7 +627,7 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX * disconnect: /* close connection */ - talloc_free(c.out.dcerpc_pipe); + talloc_unlink(ctx, c.out.dcerpc_pipe); return status; } -- cgit From 20c7c27322e95ab75ea711a825e593b0adac9114 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Thu, 24 Dec 2009 05:43:21 +0200 Subject: s4-libnet: Python binding for libnet_SetPassword() Signed-off-by: Jelmer Vernooij --- source4/libnet/py_net.c | 72 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 6 deletions(-) (limited to 'source4') diff --git a/source4/libnet/py_net.c b/source4/libnet/py_net.c index 4d3e81ce26..01afe595c4 100644 --- a/source4/libnet/py_net.c +++ b/source4/libnet/py_net.c @@ -1,18 +1,19 @@ -/* +/* Unix SMB/CIFS implementation. Samba utility functions Copyright (C) Jelmer Vernooij 2008 - + Copyright (C) Kamen Mazdrashki 2009 + 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 3 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, see . */ @@ -77,7 +78,7 @@ static PyObject *py_net_join(PyObject *cls, PyObject *args, PyObject *kwargs) return NULL; } - result = Py_BuildValue("sss", r.out.join_password, + result = Py_BuildValue("sss", r.out.join_password, dom_sid_string(mem_ctx, r.out.domain_sid), r.out.domain_name); @@ -89,11 +90,69 @@ static PyObject *py_net_join(PyObject *cls, PyObject *args, PyObject *kwargs) return result; } -static char py_net_join_doc[] = "join(domain_name, netbios_name, join_type, level) -> (join_password, domain_sid, domain_name)\n\n" \ +static PyObject *py_net_set_password(PyObject *cls, PyObject *args, PyObject *kwargs) +{ + union libnet_SetPassword r; + NTSTATUS status; + PyObject *py_creds; + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct libnet_context *libnet_ctx; + struct cli_credentials *creds; + const char *kwnames[] = { "account_name", "domain_name", "newpassword", "credentials", NULL }; + + r.generic.level = LIBNET_SET_PASSWORD_GENERIC; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sssO:SetPassword", discard_const_p(char *, kwnames), + &r.generic.in.account_name, &r.generic.in.domain_name, + &r.generic.in.newpassword, &py_creds)) { + return NULL; + } + + // FIXME: we really need to get a context from the caller or we may end + // up with 2 event contexts + ev = s4_event_context_init(NULL); + mem_ctx = talloc_new(ev); + + creds = cli_credentials_from_py_object(py_creds); + if (creds == NULL) { + PyErr_SetString(PyExc_TypeError, "Expected credentials object"); + return NULL; + } + + dcerpc_init(py_default_loadparm_context(NULL)); + + libnet_ctx = py_net_ctx(cls, ev, creds); + + status = libnet_SetPassword(libnet_ctx, mem_ctx, &r); + if (NT_STATUS_IS_ERR(status)) { + PyErr_SetString(PyExc_RuntimeError, r.generic.out.error_string); + talloc_free(mem_ctx); + return NULL; + } + + Py_RETURN_NONE; +} + +static const char py_net_join_doc[] = "join(domain_name, netbios_name, join_type, level) -> (join_password, domain_sid, domain_name)\n\n" \ "Join the domain with the specified name."; +static const char py_net_set_password_doc[] = "SetPassword(account_name, domain_name, newpassword) -> True\n\n" \ +"Set password for a user. You must supply credential with enough rights to do this.\n\n" \ +"Sample usage is:\n" \ +"creds = samba.credentials.Credentials()\n" \ +"creds.set_username('admin_user')\n" \ +"creds.set_domain('domain_name')\n" \ +"creds.set_password('pass')\n\n" \ +"net.SetPassword(account_name=,\n" \ +" domain_name=creds.get_domain(),\n" \ +" newpassword=new_pass,\n" \ +" credentials=creds)\n"; + + static struct PyMethodDef net_methods[] = { {"Join", (PyCFunction)py_net_join, METH_VARARGS|METH_KEYWORDS, py_net_join_doc}, + {"SetPassword", (PyCFunction)py_net_set_password, METH_VARARGS|METH_KEYWORDS, py_net_set_password_doc}, {NULL } }; @@ -101,3 +160,4 @@ void initnet(void) { Py_InitModule("net", net_methods); } + -- cgit From 33699bb1be03f0288562c899aa8f3963ff1cc312 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Thu, 24 Dec 2009 05:50:58 +0200 Subject: s4-libnet: Simple test for net.SetPassword() python binding Signed-off-by: Jelmer Vernooij --- source4/torture/libnet/python/samr-test.py | 62 ++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 source4/torture/libnet/python/samr-test.py (limited to 'source4') diff --git a/source4/torture/libnet/python/samr-test.py b/source4/torture/libnet/python/samr-test.py new file mode 100644 index 0000000000..d68456b79d --- /dev/null +++ b/source4/torture/libnet/python/samr-test.py @@ -0,0 +1,62 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Unix SMB/CIFS implementation. +# Copyright (C) Kamen Mazdrashki 2009 +# +# 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 3 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, see . +# + +# +# Usage: +# export ACCOUNT_NAME=kamen +# export NEW_PASS=test +# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun +# PYTHONPATH="$samba4srcdir/torture/libnet/python" $SUBUNITRUN samr-test -Ukma-exch.devel/Administrator%333 +# + +import sys +import os + +from samba import net +import unittest +import samba.tests + +if not "ACCOUNT_NAME" in os.environ.keys(): + parser.error("Please supply ACCOUNT_NAME in environment") + +if not "NEW_PASS" in os.environ.keys(): + parser.error("Please supply NEW_PASS in environment") + +account_name = os.environ["ACCOUNT_NAME"] +new_pass = os.environ["NEW_PASS"] + +creds = samba.tests.cmdline_credentials + +# +# Tests start here +# + +class Libnet_SetPwdTest(unittest.TestCase): + + ######################################################################################## + + def test_SetPassword(self): + net.SetPassword(account_name=account_name, + domain_name=creds.get_domain(), + newpassword=new_pass, + credentials=creds) + + ######################################################################################## + -- cgit From ef453c63af3d29c428029aa39a5b59b0317c76ce Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 25 Dec 2009 14:48:45 +0100 Subject: py_net/libnet: Remove C++-style comments, add more error checking, move initialization of dcerpc subsystem to libnet. --- source4/libnet/libnet.c | 3 +++ source4/libnet/py_net.c | 14 +++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/libnet/libnet.c b/source4/libnet/libnet.c index b10fb65df6..86cf80b4da 100644 --- a/source4/libnet/libnet.c +++ b/source4/libnet/libnet.c @@ -42,6 +42,9 @@ struct libnet_context *libnet_context_init(struct tevent_context *ev, ctx->event_ctx = ev; ctx->lp_ctx = lp_ctx; + /* make sure dcerpc is initialized */ + dcerpc_init(lp_ctx); + /* name resolution methods */ ctx->resolve_ctx = lp_resolve_context(lp_ctx); diff --git a/source4/libnet/py_net.c b/source4/libnet/py_net.c index 01afe595c4..e5ca5e1c97 100644 --- a/source4/libnet/py_net.c +++ b/source4/libnet/py_net.c @@ -66,10 +66,16 @@ static PyObject *py_net_join(PyObject *cls, PyObject *args, PyObject *kwargs) creds = cli_credentials_from_py_object(py_creds); if (creds == NULL) { PyErr_SetString(PyExc_TypeError, "Expected credentials object"); + talloc_free(mem_ctx); return NULL; } libnet_ctx = py_net_ctx(cls, ev, creds); + if (libnet_ctx == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Unable to initialize libnet"); + talloc_free(mem_ctx); + return NULL; + } status = libnet_Join(libnet_ctx, mem_ctx, &r); if (NT_STATUS_IS_ERR(status)) { @@ -109,8 +115,8 @@ static PyObject *py_net_set_password(PyObject *cls, PyObject *args, PyObject *kw return NULL; } - // FIXME: we really need to get a context from the caller or we may end - // up with 2 event contexts + /* FIXME: we really need to get a context from the caller or we may end + * up with 2 event contexts */ ev = s4_event_context_init(NULL); mem_ctx = talloc_new(ev); @@ -120,8 +126,6 @@ static PyObject *py_net_set_password(PyObject *cls, PyObject *args, PyObject *kw return NULL; } - dcerpc_init(py_default_loadparm_context(NULL)); - libnet_ctx = py_net_ctx(cls, ev, creds); status = libnet_SetPassword(libnet_ctx, mem_ctx, &r); @@ -158,6 +162,6 @@ static struct PyMethodDef net_methods[] = { void initnet(void) { - Py_InitModule("net", net_methods); + Py_InitModule3("net", net_methods, NULL); } -- cgit From 72d93599d95cd8bb57823fd0d4934ca4373d162c Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 27 Dec 2009 17:30:59 +0100 Subject: python: Remove sys.path line rather than updating it when installing to python system path. --- source4/Makefile | 2 +- source4/script/installmisc.sh | 40 +++++++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 14 deletions(-) (limited to 'source4') diff --git a/source4/Makefile b/source4/Makefile index 6a99ea3160..0da1ee2626 100644 --- a/source4/Makefile +++ b/source4/Makefile @@ -243,7 +243,7 @@ installman:: manpages installdirs @$(SHELL) $(srcdir)/script/installman.sh $(DESTDIR)$(mandir) $(MANPAGES) installmisc:: installdirs - @$(SHELL) $(srcdir)/script/installmisc.sh $(srcdir) $(DESTDIR)$(setupdir) $(DESTDIR)$(bindir) $(DESTDIR)$(sbindir) $(pythondir) + @$(SHELL) $(srcdir)/script/installmisc.sh "$(DESTDIR)" $(srcdir) $(DESTDIR)$(setupdir) $(DESTDIR)$(bindir) $(DESTDIR)$(sbindir) $(pythondir) $(PYTHON) installpc:: installdirs @$(SHELL) $(srcdir)/script/installpc.sh $(builddir) $(DESTDIR)$(pkgconfigdir) $(PC_FILES) diff --git a/source4/script/installmisc.sh b/source4/script/installmisc.sh index cb618628b0..c25b052dde 100755 --- a/source4/script/installmisc.sh +++ b/source4/script/installmisc.sh @@ -1,28 +1,42 @@ #!/bin/sh # install miscellaneous files -[ $# -eq 5 ] || { - echo "Usage: installmisc.sh SRCDIR SETUPDIR BINDDIR SBINDDIR PYTHONDIR" +[ $# -eq 7 ] || { + echo "Usage: installmisc.sh DESTDIR SRCDIR SETUPDIR BINDDIR SBINDDIR PYTHONDIR PYTHON" exit 1 } -SRCDIR="$1" -SETUPDIR="$2" -BINDIR="$3" -SBINDIR="$4" -PYTHONDIR="$5" +DESTDIR="$1" +SRCDIR="$2" +SETUPDIR="$3" +BINDIR="$4" +SBINDIR="$5" +PYTHONDIR="$6" +PYTHON="$7" cd $SRCDIR || exit 1 +if $PYTHON -c "import sys; sys.exit('$PYTHONDIR' in sys.path)"; then + PYTHON_PATH_NEEDS_FIXING=yes + echo "sys.path in python scripts will be updated to include $PYTHONDIR" +else + PYTHON_PATH_NEEDS_FIXING=no +fi + # fixup a python script to use the right path fix_python_path() { f="$1" - egrep 'sys.path.insert.*bin/python' $f > /dev/null && { - # old systems don't have sed -i :-( - sed "s|\(sys.path.insert.*\)bin/python\(.*\)$|\1$PYTHONDIR\2|g" < $f > $f.$$ || exit 1 - mv -f $f.$$ $f || exit 1 - chmod +x $f - } + if egrep 'sys.path.insert.*bin/python' $f > /dev/null; then + if [ "$PYTHON_PATH_NEEDS_FIXING" = "yes" ]; then + # old systems don't have sed -i :-( + sed "s|\(sys.path.insert.*\)bin/python\(.*\)$|\1$PYTHONDIR\2|g" < $f > $f.$$ || exit 1 + else + # old systems don't have sed -i :-( + sed "s|\(sys.path.insert.*\)bin/python\(.*\)$||g" < $f > $f.$$ || exit 1 + fi + mv -f $f.$$ $f || exit 1 + chmod +x $f + fi } echo "Installing setup templates" -- cgit From 8ab62799edc0f445350de73f0e8c9e2ee9ebe168 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 24 Dec 2009 21:47:53 +0100 Subject: s4:ntlmssp: fix whitespaces in ntlmssp.h metze --- source4/auth/ntlmssp/ntlmssp.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp.h b/source4/auth/ntlmssp/ntlmssp.h index 7743e7697e..f596cb81ee 100644 --- a/source4/auth/ntlmssp/ntlmssp.h +++ b/source4/auth/ntlmssp/ntlmssp.h @@ -1,20 +1,20 @@ -/* +/* Unix SMB/CIFS implementation. SMB parameters and setup Copyright (C) Andrew Tridgell 1992-1997 Copyright (C) Luke Kenneth Casson Leighton 1996-1997 Copyright (C) Paul Ashton 1997 - + 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 3 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, see . */ @@ -37,7 +37,7 @@ enum ntlmssp_message_type NTLMSSP_CHALLENGE = 2, NTLMSSP_AUTH = 3, NTLMSSP_UNKNOWN = 4, - NTLMSSP_DONE = 5 /* samba final state */ + NTLMSSP_DONE = 5 /* samba final state */ }; struct gensec_ntlmssp_state @@ -65,17 +65,17 @@ struct gensec_ntlmssp_state DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */ DATA_BLOB chal; /* Random challenge as input into the actual NTLM (or NTLM2) authentication */ - DATA_BLOB lm_resp; + DATA_BLOB lm_resp; DATA_BLOB nt_resp; DATA_BLOB session_key; - + uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */ /* internal variables used by KEY_EXCH (client-supplied user session key */ DATA_BLOB encrypted_session_key; /** - * Callback to get the 'challenge' used for NTLM authentication. + * Callback to get the 'challenge' used for NTLM authentication. * * @param ntlmssp_state This structure * @return 8 bytes of challenge data, determined by the server to be the challenge for NTLM authentication @@ -84,10 +84,10 @@ struct gensec_ntlmssp_state const uint8_t *(*get_challenge)(const struct gensec_ntlmssp_state *); /** - * Callback to find if the challenge used by NTLM authentication may be modified + * Callback to find if the challenge used by NTLM authentication may be modified * * The NTLM2 authentication scheme modifies the effective challenge, but this is not compatiable with the - * current 'security=server' implementation.. + * current 'security=server' implementation.. * * @param ntlmssp_state This structure * @return Can the challenge be set to arbitary values? @@ -96,7 +96,7 @@ struct gensec_ntlmssp_state bool (*may_set_challenge)(const struct gensec_ntlmssp_state *); /** - * Callback to set the 'challenge' used for NTLM authentication. + * Callback to set the 'challenge' used for NTLM authentication. * * The callback may use the void *auth_context to store state information, but the same value is always available * from the DATA_BLOB chal on this structure. @@ -108,21 +108,21 @@ struct gensec_ntlmssp_state NTSTATUS (*set_challenge)(struct gensec_ntlmssp_state *, DATA_BLOB *challenge); /** - * Callback to check the user's password. + * Callback to check the user's password. * - * The callback must reads the feilds of this structure for the information it needs on the user + * The callback must reads the feilds of this structure for the information it needs on the user * @param ntlmssp_state This structure * @param nt_session_key If an NT session key is returned by the authentication process, return it here * @param lm_session_key If an LM session key is returned by the authentication process, return it here * */ - NTSTATUS (*check_password)(struct gensec_ntlmssp_state *, - TALLOC_CTX *mem_ctx, + NTSTATUS (*check_password)(struct gensec_ntlmssp_state *, + TALLOC_CTX *mem_ctx, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key); const char *server_name; - bool doing_ntlm2; + bool doing_ntlm2; union { /* NTLM */ -- cgit From af25fb55c0adb8ca0b552ace607ee285023c2652 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 11:51:37 +0100 Subject: s4:auth: remove autogenerated auth/ntlm/auth_proto.h metze --- source4/auth/ntlm/auth_proto.h | 50 ------------------------------------------ 1 file changed, 50 deletions(-) delete mode 100644 source4/auth/ntlm/auth_proto.h (limited to 'source4') diff --git a/source4/auth/ntlm/auth_proto.h b/source4/auth/ntlm/auth_proto.h deleted file mode 100644 index 5e8c725ea0..0000000000 --- a/source4/auth/ntlm/auth_proto.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef __AUTH_NTLM_AUTH_PROTO_H__ -#define __AUTH_NTLM_AUTH_PROTO_H__ - -#undef _PRINTF_ATTRIBUTE -#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2) -/* This file was automatically generated by mkproto.pl. DO NOT EDIT */ - -/* this file contains prototypes for functions that are private - * to this subsystem or library. These functions should not be - * used outside this particular subsystem! */ - - -/* The following definitions come from auth/ntlm/auth.c */ - - -/*************************************************************************** - Set a fixed challenge -***************************************************************************/ -bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) ; -const struct auth_operations *auth_backend_byname(const char *name); -const struct auth_critical_sizes *auth_interface_version(void); -NTSTATUS server_service_auth_init(void); - -/* The following definitions come from auth/ntlm/auth_util.c */ - -NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, uint8_t chal[8]); - -/**************************************************************************** - Create an auth_usersupplied_data structure after appropriate mapping. -****************************************************************************/ -NTSTATUS map_user_info(TALLOC_CTX *mem_ctx, - const char *default_domain, - const struct auth_usersupplied_info *user_info, - struct auth_usersupplied_info **user_info_mapped); - -/**************************************************************************** - Create an auth_usersupplied_data structure after appropriate mapping. -****************************************************************************/ -NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, - enum auth_password_state to_state, - const struct auth_usersupplied_info *user_info_in, - const struct auth_usersupplied_info **user_info_encrypted); - -/* The following definitions come from auth/ntlm/auth_simple.c */ - -#undef _PRINTF_ATTRIBUTE -#define _PRINTF_ATTRIBUTE(a1, a2) - -#endif /* __AUTH_NTLM_AUTH_PROTO_H__ */ - -- cgit From 27349a68ea11493029bf0dbdf7399b70d7fe6ea4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 11:40:09 +0100 Subject: s4:auth: make auth_challenge_may_be_modified() public metze --- source4/auth/auth.h | 2 +- source4/auth/ntlm/auth.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/auth/auth.h b/source4/auth/auth.h index 28b955a516..f4e3b2038c 100644 --- a/source4/auth/auth.h +++ b/source4/auth/auth.h @@ -284,7 +284,7 @@ NTSTATUS auth_check_password_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct auth_serversupplied_info **server_info); - +bool auth_challenge_may_be_modified(struct auth_context *auth_ctx); NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by); NTSTATUS samba_server_gensec_start(TALLOC_CTX *mem_ctx, diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c index fafaf9cbb2..d5df387d80 100644 --- a/source4/auth/ntlm/auth.c +++ b/source4/auth/ntlm/auth.c @@ -43,7 +43,7 @@ _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, cons /*************************************************************************** Set a fixed challenge ***************************************************************************/ -bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) +_PUBLIC_ bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) { return auth_ctx->challenge.may_be_modified; } -- cgit From 8b68349442a37d987b496344133d309f8af853cb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 11:50:46 +0100 Subject: s4:auth: add auth_get_server_info_principal() prototype to auth.h metze --- source4/auth/auth.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source4') diff --git a/source4/auth/auth.h b/source4/auth/auth.h index f4e3b2038c..fa2329df32 100644 --- a/source4/auth/auth.h +++ b/source4/auth/auth.h @@ -287,6 +287,11 @@ NTSTATUS auth_check_password_recv(struct tevent_req *req, bool auth_challenge_may_be_modified(struct auth_context *auth_ctx); NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by); +NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx, + struct auth_context *auth_ctx, + const char *principal, + struct auth_serversupplied_info **server_info); + NTSTATUS samba_server_gensec_start(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx, struct messaging_context *msg_ctx, -- cgit From c064549e2e29b1a7e100300fa7d851451a90a6a7 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 01:04:33 +0100 Subject: net: Support implementing subcommands in python. --- source4/scripting/python/samba/netcmd/__init__.py | 33 +++++++++++ source4/utils/net/net.c | 71 ++++++++++++++++++++++- 2 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 source4/scripting/python/samba/netcmd/__init__.py (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py new file mode 100644 index 0000000000..54f3134d2f --- /dev/null +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2009 +# +# 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 3 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, see . +# + +class Command(object): + """A net command.""" + + def _get_description(self): + return self.__doc__ + + description = property(_get_description) + + def run(self): + """Run the command. This should be overriden by all subclasses.""" + raise NotImplementedError(self.run) + + +commands = {} diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c index 828e46889e..29d736fb15 100644 --- a/source4/utils/net/net.c +++ b/source4/utils/net/net.c @@ -6,6 +6,7 @@ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org) Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org) Copyright (C) 2004 Stefan Metzmacher (metze@samba.org) + Copyright (C) 2009 Jelmer Vernooij (jelmer@samba.org) Largely rewritten by metze in August 2004 @@ -48,6 +49,8 @@ #include "param/param.h" #include "lib/events/events.h" #include "auth/credentials/credentials.h" +#include +#include "scripting/python/modules.h" /* run a function from a function table. If not found then @@ -112,13 +115,12 @@ static const struct net_functable net_functable[] = { {NULL, NULL, NULL, NULL} }; -int net_help(struct net_context *ctx, const struct net_functable *ftable) +static int net_help_builtin(const struct net_functable *ftable) { int i = 0; const char *name = ftable[i].name; const char *desc = ftable[i].desc; - d_printf("Available commands:\n"); while (name && desc) { if (strlen(name) > 7) { d_printf("\t%s\t%s", name, desc); @@ -128,7 +130,65 @@ int net_help(struct net_context *ctx, const struct net_functable *ftable) name = ftable[++i].name; desc = ftable[i].desc; } + return 0; +} + +static int net_help_python(void) +{ + PyObject *netcmd_module; + PyObject *py_cmds; + PyObject *key, *value; + Py_ssize_t pos = 0; + + netcmd_module = PyImport_ImportModule("samba.netcmd"); + if (netcmd_module == NULL) { + PyErr_Print(); + return 1; + } + + py_cmds = PyObject_GetAttrString(netcmd_module, "commands"); + if (py_cmds == NULL) { + PyErr_Print(); + return 1; + } + if (!PyDict_Check(py_cmds)) { + fprintf(stderr, "Python net commands is not a dictionary\n"); + return 1; + } + + while (PyDict_Next(py_cmds, &pos, &key, &value)) { + char *name, *desc; + PyObject *py_desc; + if (!PyString_Check(key)) { + fprintf(stderr, "Command name not a string\n"); + return 1; + } + name = PyString_AsString(key); + py_desc = PyObject_GetAttrString(value, "description"); + if (py_desc == NULL) { + PyErr_Print(); + return 1; + } + if (!PyString_Check(py_desc)) { + fprintf(stderr, "Command description for %s not a string\n", name); + return 1; + } + desc = PyString_AsString(py_desc); + if (strlen(name) > 7) { + d_printf("\t%s\t%s", name, desc); + } else { + d_printf("\t%s\t\t%s", name, desc); + } + } + return 0; +} + +int net_help(struct net_context *ctx, const struct net_functable *ftable) +{ + d_printf("Available commands:\n"); + net_help_builtin(ftable); + net_help_python(); return 0; } @@ -208,7 +268,12 @@ static int binary_net(int argc, const char **argv) ctx->credentials = cmdline_credentials; ctx->event_ctx = ev; - rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable, net_usage); + py_load_samba_modules(); + Py_Initialize(); + py_update_path("bin"); /* FIXME: Can't assume this is always the case */ + + rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable, + net_usage); if (rc != 0) { DEBUG(0,("return code = %d\n", rc)); -- cgit From 9b1a21031187e83de61d999b70a6d1cda7b68444 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 01:21:27 +0100 Subject: net: Support usage/help of subcommands implemented in Python. --- source4/scripting/python/samba/netcmd/__init__.py | 4 ++ source4/utils/net/net.c | 70 ++++++++++++++++++----- 2 files changed, 60 insertions(+), 14 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index 54f3134d2f..f644febba6 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -23,6 +23,9 @@ class Command(object): def _get_description(self): return self.__doc__ + def usage(self): + raise NotImplementedError + description = property(_get_description) def run(self): @@ -31,3 +34,4 @@ class Command(object): commands = {} +commands["foo"] = Command() diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c index 29d736fb15..298204b01f 100644 --- a/source4/utils/net/net.c +++ b/source4/utils/net/net.c @@ -52,6 +52,29 @@ #include #include "scripting/python/modules.h" +static PyObject *py_commands(void) +{ + PyObject *netcmd_module, *py_cmds; + netcmd_module = PyImport_ImportModule("samba.netcmd"); + if (netcmd_module == NULL) { + PyErr_Print(); + return NULL; + } + + py_cmds = PyObject_GetAttrString(netcmd_module, "commands"); + if (py_cmds == NULL) { + PyErr_Print(); + return NULL; + } + + if (!PyDict_Check(py_cmds)) { + fprintf(stderr, "Python net commands is not a dictionary\n"); + return NULL; + } + + return py_cmds; +} + /* run a function from a function table. If not found then call the specified usage function @@ -62,6 +85,7 @@ int net_run_function(struct net_context *ctx, int (*usage_fn)(struct net_context *ctx, int argc, const char **argv)) { int i; + PyObject *py_cmds, *py_cmd; if (argc == 0) { return usage_fn(ctx, argc, argv); @@ -75,6 +99,21 @@ int net_run_function(struct net_context *ctx, return functable[i].fn(ctx, argc-1, argv+1); } + py_cmds = py_commands(); + if (py_cmds == NULL) { + return 1; + } + + py_cmd = PyDict_GetItemString(py_cmds, argv[0]); + if (py_cmd != NULL) { + PyObject *ret = PyObject_CallMethod(py_cmd, "run", ""); + if (ret == NULL) { + PyErr_Print(); + return 1; + } + return PyInt_AsLong(ret); + } + d_printf("No command: %s\n", argv[0]); return usage_fn(ctx, argc, argv); } @@ -87,6 +126,7 @@ int net_run_usage(struct net_context *ctx, const struct net_functable *functable) { int i; + PyObject *py_cmds, *py_cmd; for (i=0; functable[i].name; i++) { if (strcasecmp_m(argv[0], functable[i].name) == 0) @@ -95,6 +135,21 @@ int net_run_usage(struct net_context *ctx, } } + py_cmds = py_commands(); + if (py_cmds == NULL) { + return 1; + } + + py_cmd = PyDict_GetItemString(py_cmds, argv[0]); + if (py_cmd != NULL) { + PyObject *ret = PyObject_CallMethod(py_cmd, "usage", ""); + if (ret == NULL) { + PyErr_Print(); + return 1; + } + return PyInt_AsLong(ret); + } + d_printf("No usage information for command: %s\n", argv[0]); return 1; @@ -135,25 +190,12 @@ static int net_help_builtin(const struct net_functable *ftable) static int net_help_python(void) { - PyObject *netcmd_module; PyObject *py_cmds; PyObject *key, *value; Py_ssize_t pos = 0; - netcmd_module = PyImport_ImportModule("samba.netcmd"); - if (netcmd_module == NULL) { - PyErr_Print(); - return 1; - } - - py_cmds = PyObject_GetAttrString(netcmd_module, "commands"); + py_cmds = py_commands(); if (py_cmds == NULL) { - PyErr_Print(); - return 1; - } - - if (!PyDict_Check(py_cmds)) { - fprintf(stderr, "Python net commands is not a dictionary\n"); return 1; } -- cgit From 9e603dfb95f61a7daf2acc80c9c3120ae9ecf98e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 13:53:18 +0100 Subject: s4/net: Support parsing arguments in Python commands. --- source4/scripting/python/samba/netcmd/__init__.py | 64 ++++++++++++++++++++-- source4/utils/net/net.c | 65 ++++++++++++++++++----- 2 files changed, 112 insertions(+), 17 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index f644febba6..16f19f8b24 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -17,21 +17,79 @@ # along with this program. If not, see . # +import optparse +from samba import getopt as options, Ldb + + +class Option(optparse.Option): + pass + + class Command(object): """A net command.""" def _get_description(self): - return self.__doc__ + return self.__doc__.splitlines()[-1].rstrip("\n") + + def _get_name(self): + name = self.__class__.__name__ + if name.startswith("cmd_"): + return name[4:] + return name + + name = property(_get_name) def usage(self): - raise NotImplementedError + self.parser.print_usage() description = property(_get_description) + takes_args = [] + takes_options = [] + + def __init__(self): + synopsis = self.name + if self.takes_args: + synopsis += " " + " ".join(self.takes_args) + self.parser = optparse.OptionParser(synopsis) + self.parser.add_options(self.takes_options) + + def _run(self, *argv): + opts, args = self.parser.parse_args(list(argv)) + return self.run(*args, **opts.__dict__) + def run(self): """Run the command. This should be overriden by all subclasses.""" raise NotImplementedError(self.run) +class SuperCommand(Command): + """A command with subcommands.""" + + subcommands = {} + + def run(self, subcommand, *args, **kwargs): + if not subcommand in subcommands: + print >>sys.stderr, "No such subcommand '%s'" % subcommand + return subcommands[subcommand].run(*args, **kwargs) + + def usage(self, subcommand=None, *args, **kwargs): + if subcommand is None: + print "Available subcommands" + for subcommand in subcommands: + print "\t%s" % subcommand + return 0 + else: + if not subcommand in subcommands: + print >>sys.stderr, "No such subcommand '%s'" % subcommand + return subcommands[subcommand].usage(*args, **kwargs) + + +class FooCommand(Command): + + def run(self, bar): + print "LALALA" + bar + return 0 + commands = {} -commands["foo"] = Command() +commands["foo"] = FooCommand() diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c index 298204b01f..31bade32a5 100644 --- a/source4/utils/net/net.c +++ b/source4/utils/net/net.c @@ -52,6 +52,51 @@ #include #include "scripting/python/modules.h" +static PyObject *py_tuple_from_argv(int argc, const char *argv[]) +{ + PyObject *l; + Py_ssize_t i; + + l = PyTuple_New(argc); + if (l == NULL) { + return NULL; + } + + for (i = 0; i < argc; i++) { + PyTuple_SetItem(l, i, PyString_FromString(argv[i])); + } + + return l; +} + +static int py_call_with_string_args(PyObject *self, const char *method, int argc, const char *argv[]) +{ + PyObject *ret, *args, *py_method; + + args = py_tuple_from_argv(argc, argv); + if (args == NULL) { + PyErr_Print(); + return 1; + } + + py_method = PyObject_GetAttrString(self, method); + if (py_method == NULL) { + PyErr_Print(); + return 1; + } + + ret = PyObject_CallObject(py_method, args); + + Py_DECREF(args); + + if (ret == NULL) { + PyErr_Print(); + return 1; + } + + return PyInt_AsLong(ret); +} + static PyObject *py_commands(void) { PyObject *netcmd_module, *py_cmds; @@ -106,12 +151,8 @@ int net_run_function(struct net_context *ctx, py_cmd = PyDict_GetItemString(py_cmds, argv[0]); if (py_cmd != NULL) { - PyObject *ret = PyObject_CallMethod(py_cmd, "run", ""); - if (ret == NULL) { - PyErr_Print(); - return 1; - } - return PyInt_AsLong(ret); + return py_call_with_string_args(py_cmd, "_run", + argc-1, argv+1); } d_printf("No command: %s\n", argv[0]); @@ -142,12 +183,8 @@ int net_run_usage(struct net_context *ctx, py_cmd = PyDict_GetItemString(py_cmds, argv[0]); if (py_cmd != NULL) { - PyObject *ret = PyObject_CallMethod(py_cmd, "usage", ""); - if (ret == NULL) { - PyErr_Print(); - return 1; - } - return PyInt_AsLong(ret); + return py_call_with_string_args(py_cmd, "usage", argc-1, + argv+1); } d_printf("No usage information for command: %s\n", argv[0]); @@ -218,9 +255,9 @@ static int net_help_python(void) } desc = PyString_AsString(py_desc); if (strlen(name) > 7) { - d_printf("\t%s\t%s", name, desc); + d_printf("\t%s\t%s\n", name, desc); } else { - d_printf("\t%s\t\t%s", name, desc); + d_printf("\t%s\t\t%s\n", name, desc); } } return 0; -- cgit From 8c19cd2dea470b5f4a981bfbd4b9e33c11bfde39 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 14:17:25 +0100 Subject: netcmd: Add some basic tests. --- source4/scripting/python/samba/tests/netcmd.py | 34 ++++++++++++++++++++++++++ source4/selftest/tests.sh | 1 + 2 files changed, 35 insertions(+) create mode 100644 source4/scripting/python/samba/tests/netcmd.py (limited to 'source4') diff --git a/source4/scripting/python/samba/tests/netcmd.py b/source4/scripting/python/samba/tests/netcmd.py new file mode 100644 index 0000000000..ecd8dc439e --- /dev/null +++ b/source4/scripting/python/samba/tests/netcmd.py @@ -0,0 +1,34 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2009 +# +# 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 3 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, see . +# + +import unittest + +from samba.netcmd import Command + +class CommandTests(unittest.TestCase): + + def test_name(self): + class cmd_foo(Command): + pass + self.assertEquals("foo", cmd_foo().name) + + def test_description(self): + class cmd_foo(Command): + """Mydescription""" + self.assertEquals("Mydescription", cmd_foo().description) diff --git a/source4/selftest/tests.sh b/source4/selftest/tests.sh index fa487dbd58..cad97b7ad3 100755 --- a/source4/selftest/tests.sh +++ b/source4/selftest/tests.sh @@ -450,6 +450,7 @@ plantest "samba.python" none $SUBUNITRUN samba.tests plantest "provision.python" none $SUBUNITRUN samba.tests.provision plantest "samba3.python" none $SUBUNITRUN samba.tests.samba3 plantest "samr.python" dc:local $SUBUNITRUN samba.tests.dcerpc.sam +plantest "netcmd.python" none $SUBUNITRUN samba.tests.netcmd plantest "dcerpc.bare.python" dc:local $SUBUNITRUN samba.tests.dcerpc.bare plantest "unixinfo.python" dc:local $SUBUNITRUN samba.tests.dcerpc.unix plantest "samdb.python" none $SUBUNITRUN samba.tests.samdb -- cgit From eaf4a9afb24f2cc3cd1a268dda4ad37637821f9d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 16:04:19 +0100 Subject: s4/net: Make pwsettings a net subcommand. --- .../scripting/python/samba/netcmd/pwsettings.py | 187 +++++++++++++++++++ source4/setup/pwsettings | 198 --------------------- 2 files changed, 187 insertions(+), 198 deletions(-) create mode 100755 source4/scripting/python/samba/netcmd/pwsettings.py delete mode 100755 source4/setup/pwsettings (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/pwsettings.py b/source4/scripting/python/samba/netcmd/pwsettings.py new file mode 100755 index 0000000000..724c28e5f9 --- /dev/null +++ b/source4/scripting/python/samba/netcmd/pwsettings.py @@ -0,0 +1,187 @@ +#!/usr/bin/python +# +# Sets password settings. +# (Password complexity, history length, minimum password length, the minimum +# and maximum password age) on a Samba4 server +# +# Copyright Matthias Dieter Wallnoefer 2009 +# Copyright Andrew Kroeger 2009 +# Copyright Jelmer Vernooij 2009 +# +# 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 3 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, see . +# + +import sys + +import samba.getopt as options +import optparse +import ldb + +from samba.auth import system_session +from samba.samdb import SamDB +from samba.dcerpc.samr import DOMAIN_PASSWORD_COMPLEX +from samba.netcmd import Command, CommandError, Option + +class cmd_pwsettings(Command): + """Sets password settings. + + Password complexity, history length, minimum password length, the minimum + and maximum password age) on a Samba4 server. + """ + + synopsis = "(show | set )" + + takes_optiongroups = [ + options.SambaOptions, + options.VersionOptions, + options.CredentialsOptions, + ] + + takes_options = [ + Option("-H", help="LDB URL for database or target server", type=str), + Option("--quiet", help="Be quiet", action="store_true"), + Option("--complexity", type="choice", choices=["on","off","default"], + help="The password complexity (on | off | default). Default is 'on'"), + Option("--history-length", + help="The password history length ( | default). Default is 24.", type=str), + Option("--min-pwd-length", + help="The minimum password length ( | default). Default is 7.", type=str), + Option("--min-pwd-age", + help="The minimum password age ( | default). Default is 0.", type=str), + Option("--max-pwd-age", + help="The maximum password age ( | default). Default is 43.", type=str), + ] + + def run(self, H=None, min_pwd_age=None, max_pwd_age=None, quiet=False, + complexity=None, history_length=None, min_pwd_length=None, + username=None, simple_bind_dn=None, no_pass=None, workgroup=None, + kerberos=None, configfile=None, password=None): + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + if H is not None: + url = H + else: + url = lp.get("sam database") + + samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp) + + domain_dn = SamDB.domain_dn(samdb) + res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE, + attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength", "minPwdAge", + "maxPwdAge"]) + assert(len(res) == 1) + try: + pwd_props = int(res[0]["pwdProperties"][0]) + pwd_hist_len = int(res[0]["pwdHistoryLength"][0]) + min_pwd_len = int(res[0]["minPwdLength"][0]) + # ticks -> days + min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24)) + max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24)) + except KeyError: + raise CommandError("Could not retrieve password properties!") + + if args[0] == "show": + self.message("Password informations for domain '%s'" % domain_dn) + self.message("") + if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0: + self.message("Password complexity: on") + else: + self.message("Password complexity: off") + self.message("Password history length: %d" % pwd_hist_len) + self.message("Minimum password length: %d" % min_pwd_len) + self.message("Minimum password age (days): %d" % min_pwd_age) + self.message("Maximum password age (days): %d" % max_pwd_age) + elif args[0] == "set": + msgs = [] + m = ldb.Message() + m.dn = ldb.Dn(samdb, domain_dn) + + if complexity is not None: + if complexity == "on" or complexity == "default": + pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX + msgs.append("Password complexity activated!") + elif complexity == "off": + pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX) + msgs.append("Password complexity deactivated!") + + m["pwdProperties"] = ldb.MessageElement(str(pwd_props), + ldb.FLAG_MOD_REPLACE, "pwdProperties") + + if history_length is not None: + if history_length == "default": + pwd_hist_len = 24 + else: + pwd_hist_len = int(history_length) + + if pwd_hist_len < 0 or pwd_hist_len > 24: + raise CommandError("Password history length must be in the range of 0 to 24!") + + m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len), + ldb.FLAG_MOD_REPLACE, "pwdHistoryLength") + msgs.append("Password history length changed!") + + if min_pwd_length is not None: + if min_pwd_length == "default": + min_pwd_len = 7 + else: + min_pwd_len = int(min_pwd_length) + + if min_pwd_len < 0 or min_pwd_len > 14: + raise CommandError("Minimum password length must be in the range of 0 to 14!") + + m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len), + ldb.FLAG_MOD_REPLACE, "minPwdLength") + msgs.append("Minimum password length changed!") + + if min_pwd_age is not None: + if min_pwd_age == "default": + min_pwd_age = 0 + else: + min_pwd_age = int(min_pwd_age) + + if min_pwd_age < 0 or min_pwd_age > 998: + raise CommandError("Minimum password age must be in the range of 0 to 998!") + + # days -> ticks + min_pwd_age_ticks = -int(min_pwd_age * (24 * 60 * 60 * 1e7)) + + m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age_ticks), + ldb.FLAG_MOD_REPLACE, "minPwdAge") + msgs.append("Minimum password age changed!") + + if max_pwd_age is not None: + if max_pwd_age == "default": + max_pwd_age = 43 + else: + max_pwd_age = int(max_pwd_age) + + if max_pwd_age < 0 or max_pwd_age > 999: + raise CommandError("Maximum password age must be in the range of 0 to 999!") + + # days -> ticks + max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7)) + + m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age_ticks), + ldb.FLAG_MOD_REPLACE, "maxPwdAge") + msgs.append("Maximum password age changed!") + + if max_pwd_age > 0 and min_pwd_age >= max_pwd_age: + raise CommandError("Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age)) + + samdb.modify(m) + msgs.append("All changes applied successfully!") + self.message("\n".join(msgs)) + else: + raise CommandError("Wrong argument '" + args[0] + "'!") diff --git a/source4/setup/pwsettings b/source4/setup/pwsettings deleted file mode 100755 index 59ed5d29bf..0000000000 --- a/source4/setup/pwsettings +++ /dev/null @@ -1,198 +0,0 @@ -#!/usr/bin/python -# -# Sets password settings (Password complexity, history length, minimum password -# length, the minimum and maximum password age) on a Samba4 server -# -# Copyright Matthias Dieter Wallnoefer 2009 -# Copyright Andrew Kroeger 2009 -# -# 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 3 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, see . -# - -import sys - -# Find right directory when running from source tree -sys.path.insert(0, "bin/python") - -import samba.getopt as options -import optparse -import ldb - -from samba.auth import system_session -from samba.samdb import SamDB -from samba.dcerpc.samr import DOMAIN_PASSWORD_COMPLEX - -parser = optparse.OptionParser("pwsettings (show | set )") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) -parser.add_option_group(options.VersionOptions(parser)) -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) -parser.add_option("-H", help="LDB URL for database or target server", type=str) -parser.add_option("--quiet", help="Be quiet", action="store_true") -parser.add_option("--complexity", type="choice", choices=["on","off","default"], - help="The password complexity (on | off | default). Default is 'on'") -parser.add_option("--history-length", - help="The password history length ( | default). Default is 24.", type=str) -parser.add_option("--min-pwd-length", - help="The minimum password length ( | default). Default is 7.", type=str) -parser.add_option("--min-pwd-age", - help="The minimum password age ( | default). Default is 0.", type=str) -parser.add_option("--max-pwd-age", - help="The maximum password age ( | default). Default is 43.", type=str) - -opts, args = parser.parse_args() - -# -# print a message if quiet is not set -# -def message(text): - if not opts.quiet: - print text - -if len(args) == 0: - parser.print_usage() - sys.exit(1) - -lp = sambaopts.get_loadparm() -creds = credopts.get_credentials(lp) - -if opts.H is not None: - url = opts.H -else: - url = lp.get("sam database") - -samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp) - -domain_dn = SamDB.domain_dn(samdb) -res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE, - attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength", "minPwdAge", - "maxPwdAge"]) -assert(len(res) == 1) -try: - pwd_props = int(res[0]["pwdProperties"][0]) - pwd_hist_len = int(res[0]["pwdHistoryLength"][0]) - min_pwd_len = int(res[0]["minPwdLength"][0]) - # ticks -> days - min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24)) - max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24)) -except KeyError: - print >>sys.stderr, "ERROR: Could not retrieve password properties!" - if args[0] == "show": - print >>sys.stderr, "So no settings can be displayed!" - sys.exit(1) - -if args[0] == "show": - message("Password informations for domain '" + domain_dn + "'") - message("") - if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0: - message("Password complexity: on") - else: - message("Password complexity: off") - message("Password history length: " + str(pwd_hist_len)) - message("Minimum password length: " + str(min_pwd_len)) - message("Minimum password age (days): " + str(min_pwd_age)) - message("Maximum password age (days): " + str(max_pwd_age)) - -elif args[0] == "set": - - msgs = [] - m = ldb.Message() - m.dn = ldb.Dn(samdb, domain_dn) - - if opts.complexity is not None: - if opts.complexity == "on" or opts.complexity == "default": - pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX - msgs.append("Password complexity activated!") - elif opts.complexity == "off": - pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX) - msgs.append("Password complexity deactivated!") - - m["pwdProperties"] = ldb.MessageElement(str(pwd_props), - ldb.FLAG_MOD_REPLACE, "pwdProperties") - - if opts.history_length is not None: - if opts.history_length == "default": - pwd_hist_len = 24 - else: - pwd_hist_len = int(opts.history_length) - - if pwd_hist_len < 0 or pwd_hist_len > 24: - print >>sys.stderr, "ERROR: Password history length must be in the range of 0 to 24!" - sys.exit(1) - - m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len), - ldb.FLAG_MOD_REPLACE, "pwdHistoryLength") - msgs.append("Password history length changed!") - - if opts.min_pwd_length is not None: - if opts.min_pwd_length == "default": - min_pwd_len = 7 - else: - min_pwd_len = int(opts.min_pwd_length) - - if min_pwd_len < 0 or min_pwd_len > 14: - print >>sys.stderr, "ERROR: Minimum password length must be in the range of 0 to 14!" - sys.exit(1) - - m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len), - ldb.FLAG_MOD_REPLACE, "minPwdLength") - msgs.append("Minimum password length changed!") - - if opts.min_pwd_age is not None: - if opts.min_pwd_age == "default": - min_pwd_age = 0 - else: - min_pwd_age = int(opts.min_pwd_age) - - if min_pwd_age < 0 or min_pwd_age > 998: - print >>sys.stderr, "ERROR: Minimum password age must be in the range of 0 to 998!" - sys.exit(1) - - # days -> ticks - min_pwd_age_ticks = -int(min_pwd_age * (24 * 60 * 60 * 1e7)) - - m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age_ticks), - ldb.FLAG_MOD_REPLACE, "minPwdAge") - msgs.append("Minimum password age changed!") - - if opts.max_pwd_age is not None: - if opts.max_pwd_age == "default": - max_pwd_age = 43 - else: - max_pwd_age = int(opts.max_pwd_age) - - if max_pwd_age < 0 or max_pwd_age > 999: - print >>sys.stderr, "ERROR: Maximum password age must be in the range of 0 to 999!" - sys.exit(1) - - # days -> ticks - max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7)) - - m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age_ticks), - ldb.FLAG_MOD_REPLACE, "maxPwdAge") - msgs.append("Maximum password age changed!") - - if max_pwd_age > 0 and min_pwd_age >= max_pwd_age: - print "ERROR: Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age) - sys.exit(1) - - samdb.modify(m) - - msgs.append("All changes applied successfully!") - - message("\n".join(msgs)) -else: - print >>sys.stderr, "ERROR: Wrong argument '" + args[0] + "'!" - sys.exit(1) -- cgit From 732a7630e9db2578c3a46d0836aaf602e1d5c604 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 16:05:04 +0100 Subject: Use CommandError exception to deal with problems during net commands. --- source4/scripting/python/samba/getopt.py | 14 ++++---- source4/scripting/python/samba/netcmd/__init__.py | 40 +++++++++++++++-------- 2 files changed, 34 insertions(+), 20 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index 8b756b2d6f..48d48dc260 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -2,17 +2,17 @@ # Samba-specific bits for optparse # Copyright (C) Jelmer Vernooij 2007 -# +# # 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 3 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, see . # @@ -30,7 +30,7 @@ class SambaOptions(optparse.OptionGroup): def __init__(self, parser): optparse.OptionGroup.__init__(self, parser, "Samba Common Options") self.add_option("-s", "--configfile", action="callback", - type=str, metavar="FILE", help="Configuration file", + type=str, metavar="FILE", help="Configuration file", callback=self._load_configfile) self._configfile = None @@ -73,15 +73,15 @@ class CredentialsOptions(optparse.OptionGroup): help="DN to use for a simple bind") self.add_option("--password", metavar="PASSWORD", action="callback", help="Password", type=str, callback=self._set_password) - self.add_option("-U", "--username", metavar="USERNAME", + self.add_option("-U", "--username", metavar="USERNAME", action="callback", type=str, help="Username", callback=self._parse_username) - self.add_option("-W", "--workgroup", metavar="WORKGROUP", + self.add_option("-W", "--workgroup", metavar="WORKGROUP", action="callback", type=str, help="Workgroup", callback=self._parse_workgroup) self.add_option("-N", "--no-pass", action="store_true", help="Don't ask for a password") - self.add_option("-k", "--kerberos", metavar="KERBEROS", + self.add_option("-k", "--kerberos", metavar="KERBEROS", action="callback", type=str, help="Use Kerberos", callback=self._set_kerberos) self.creds = Credentials() diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index 16f19f8b24..4be8977b45 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -29,7 +29,7 @@ class Command(object): """A net command.""" def _get_description(self): - return self.__doc__.splitlines()[-1].rstrip("\n") + return self.__doc__.splitlines()[0].rstrip("\n") def _get_name(self): name = self.__class__.__name__ @@ -44,15 +44,26 @@ class Command(object): description = property(_get_description) + def _get_synopsis(self): + ret = self.name + if self.takes_args: + ret += " " + " ".join(self.takes_args) + return ret + + synopsis = property(_get_synopsis) + takes_args = [] takes_options = [] + takes_optiongroups = [] def __init__(self): - synopsis = self.name - if self.takes_args: - synopsis += " " + " ".join(self.takes_args) - self.parser = optparse.OptionParser(synopsis) + self.parser = optparse.OptionParser(self.synopsis) self.parser.add_options(self.takes_options) + for optiongroup in self.takes_optiongroups: + self.parser.add_option_group(optiongroup(self.parser)) + + def message(self, text): + print text def _run(self, *argv): opts, args = self.parser.parse_args(list(argv)) @@ -70,8 +81,12 @@ class SuperCommand(Command): def run(self, subcommand, *args, **kwargs): if not subcommand in subcommands: - print >>sys.stderr, "No such subcommand '%s'" % subcommand - return subcommands[subcommand].run(*args, **kwargs) + print >>sys.stderr, "ERROR: No such subcommand '%s'" % subcommand + try: + return subcommands[subcommand].run(*args, **kwargs) + except CommandError, e: + print >>sys.stderr, "ERROR: %s" % e.message + return -1 def usage(self, subcommand=None, *args, **kwargs): if subcommand is None: @@ -81,15 +96,14 @@ class SuperCommand(Command): return 0 else: if not subcommand in subcommands: - print >>sys.stderr, "No such subcommand '%s'" % subcommand + print >>sys.stderr, "ERROR: No such subcommand '%s'" % subcommand return subcommands[subcommand].usage(*args, **kwargs) -class FooCommand(Command): +class CommandError(Exception): + pass - def run(self, bar): - print "LALALA" + bar - return 0 commands = {} -commands["foo"] = FooCommand() +from samba.netcmd.pwsettings import cmd_pwsettings +commands["pwsettings"] = cmd_pwsettings() -- cgit From 027f6ada63b34b5277fa73e5ffa6e436041d9ffb Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 16:06:04 +0100 Subject: s4/net: Use d_printf consistently when reporting errors. --- source4/utils/net/net.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c index 31bade32a5..9725402c7f 100644 --- a/source4/utils/net/net.c +++ b/source4/utils/net/net.c @@ -113,7 +113,7 @@ static PyObject *py_commands(void) } if (!PyDict_Check(py_cmds)) { - fprintf(stderr, "Python net commands is not a dictionary\n"); + d_printf("Python net commands is not a dictionary\n"); return NULL; } @@ -240,7 +240,7 @@ static int net_help_python(void) char *name, *desc; PyObject *py_desc; if (!PyString_Check(key)) { - fprintf(stderr, "Command name not a string\n"); + d_printf("Command name not a string\n"); return 1; } name = PyString_AsString(key); @@ -250,7 +250,8 @@ static int net_help_python(void) return 1; } if (!PyString_Check(py_desc)) { - fprintf(stderr, "Command description for %s not a string\n", name); + d_printf("Command description for %s not a string\n", + name); return 1; } desc = PyString_AsString(py_desc); -- cgit From e60a40e287a1febdab98cc6cf81a80a8cb6bcfb2 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 16:48:07 +0100 Subject: s4/net: Add domainlevel subcommand. --- source4/script/installmisc.sh | 2 +- source4/scripting/python/samba/netcmd/__init__.py | 39 +++- .../scripting/python/samba/netcmd/domainlevel.py | 229 +++++++++++++++++++ .../scripting/python/samba/netcmd/pwsettings.py | 33 +-- source4/setup/domainlevel | 250 --------------------- 5 files changed, 276 insertions(+), 277 deletions(-) create mode 100644 source4/scripting/python/samba/netcmd/domainlevel.py mode change 100755 => 100644 source4/scripting/python/samba/netcmd/pwsettings.py delete mode 100755 source4/setup/domainlevel (limited to 'source4') diff --git a/source4/script/installmisc.sh b/source4/script/installmisc.sh index c25b052dde..31ca7e645d 100755 --- a/source4/script/installmisc.sh +++ b/source4/script/installmisc.sh @@ -49,7 +49,7 @@ cp setup/ad-schema/*.txt $SETUPDIR/ad-schema || exit 1 cp setup/display-specifiers/*.txt $SETUPDIR/display-specifiers || exit 1 echo "Installing sbin scripts from setup/*" -for p in domainlevel enableaccount newuser provision setexpiry setpassword pwsettings +for p in domainlevel enableaccount newuser provision setexpiry setpassword do cp setup/$p $SBINDIR || exit 1 chmod a+x $SBINDIR/$p diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index 4be8977b45..5c18d29fc3 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -39,8 +39,9 @@ class Command(object): name = property(_get_name) - def usage(self): - self.parser.print_usage() + def usage(self, args): + parser, _ = self._create_parser() + parser.print_usage() description = property(_get_description) @@ -54,20 +55,34 @@ class Command(object): takes_args = [] takes_options = [] - takes_optiongroups = [] - - def __init__(self): - self.parser = optparse.OptionParser(self.synopsis) - self.parser.add_options(self.takes_options) - for optiongroup in self.takes_optiongroups: - self.parser.add_option_group(optiongroup(self.parser)) + takes_optiongroups = {} + + def _create_parser(self): + parser = optparse.OptionParser(self.synopsis) + parser.prog = "net" + parser.add_options(self.takes_options) + optiongroups = {} + for name, optiongroup in self.takes_optiongroups.iteritems(): + optiongroups[name] = optiongroup(parser) + parser.add_option_group(optiongroups[name]) + return parser, optiongroups def message(self, text): print text def _run(self, *argv): - opts, args = self.parser.parse_args(list(argv)) - return self.run(*args, **opts.__dict__) + parser, optiongroups = self._create_parser() + opts, args = parser.parse_args(list(argv)) + # Filter out options from option groups + kwargs = dict(opts.__dict__) + for option_group in parser.option_groups: + for option in option_group.option_list: + del kwargs[option.dest] + kwargs.update(optiongroups) + if len(args) < len(self.takes_args): + self.usage(args) + return -1 + return self.run(*args, **kwargs) def run(self): """Run the command. This should be overriden by all subclasses.""" @@ -107,3 +122,5 @@ class CommandError(Exception): commands = {} from samba.netcmd.pwsettings import cmd_pwsettings commands["pwsettings"] = cmd_pwsettings() +from samba.netcmd.domainlevel import cmd_domainlevel +commands["domainlevel"] = cmd_domainlevel() diff --git a/source4/scripting/python/samba/netcmd/domainlevel.py b/source4/scripting/python/samba/netcmd/domainlevel.py new file mode 100644 index 0000000000..1c12bde0c6 --- /dev/null +++ b/source4/scripting/python/samba/netcmd/domainlevel.py @@ -0,0 +1,229 @@ +#!/usr/bin/python +# +# Raises domain and forest function levels +# +# Copyright Matthias Dieter Wallnoefer 2009 +# Copyright Jelmer Vernooij 2009 +# +# 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 3 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, see . +# + +# Notice: At the moment we have some more checks to do here on the special +# attributes (consider attribute "msDS-Behavior-Version). This is due to the +# fact that we on s4 LDB don't implement their change policy (only certain +# values, only increments possible...) yet. + +import samba.getopt as options +import ldb + +from samba.auth import system_session +from samba.netcmd import ( + Command, + CommandError, + Option, + ) +from samba.samdb import SamDB +from samba import ( + DS_DOMAIN_FUNCTION_2000, + DS_DOMAIN_FUNCTION_2003, + DS_DOMAIN_FUNCTION_2003_MIXED, + DS_DOMAIN_FUNCTION_2008, + DS_DOMAIN_FUNCTION_2008_R2, + DS_DC_FUNCTION_2000, + DS_DC_FUNCTION_2003, + DS_DC_FUNCTION_2008, + DS_DC_FUNCTION_2008_R2, + ) + +class cmd_domainlevel(Command): + """Raises domain and forest function levels.""" + + synopsis = "(show | raise )" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "credopts": options.CredentialsOptions, + "versionopts": options.VersionOptions, + } + + takes_options = [ + Option("-H", help="LDB URL for database or target server", type=str), + Option("--quiet", help="Be quiet", action="store_true"), + Option("--forest", type="choice", choices=["2003", "2008", "2008_R2"], + help="The forest function level (2003 | 2008 | 2008_R2)"), + Option("--domain", type="choice", choices=["2003", "2008", "2008_R2"], + help="The domain function level (2003 | 2008 | 2008_R2)"), + ] + + takes_args = ["subcommand"] + + def run(self, subcommand, H=None, forest=None, domain=None, quiet=False, + credopts=None, sambaopts=None, versionopts=None): + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + if H is not None: + url = H + else: + url = lp.get("sam database") + + samdb = SamDB(url=url, session_info=system_session(), + credentials=creds, lp=lp) + + domain_dn = SamDB.domain_dn(samdb) + + res_forest = samdb.search("CN=Partitions,CN=Configuration," + domain_dn, + scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"]) + assert(len(res_forest) == 1) + + res_domain = samdb.search(domain_dn, scope=ldb.SCOPE_BASE, + attrs=["msDS-Behavior-Version", "nTMixedDomain"]) + assert(len(res_domain) == 1) + + res_dc_s = samdb.search("CN=Sites,CN=Configuration," + domain_dn, + scope=ldb.SCOPE_SUBTREE, expression="(objectClass=nTDSDSA)", + attrs=["msDS-Behavior-Version"]) + assert(len(res_dc_s) >= 1) + + try: + level_forest = int(res_forest[0]["msDS-Behavior-Version"][0]) + level_domain = int(res_domain[0]["msDS-Behavior-Version"][0]) + level_domain_mixed = int(res_domain[0]["nTMixedDomain"][0]) + + min_level_dc = int(res_dc_s[0]["msDS-Behavior-Version"][0]) # Init value + for msg in res_dc_s: + if int(msg["msDS-Behavior-Version"][0]) < min_level_dc: + min_level_dc = int(msg["msDS-Behavior-Version"][0]) + + if level_forest < 0 or level_domain < 0: + raise CommandError("Domain and/or forest function level(s) is/are invalid. Correct them or reprovision!") + if min_level_dc < 0: + raise CommandError("Lowest function level of a DC is invalid. Correct this or reprovision!") + if level_forest > level_domain: + raise CommandError("Forest function level is higher than the domain level(s). Correct this or reprovision!") + if level_domain > min_level_dc: + raise CommandError("Domain function level is higher than the lowest function level of a DC. Correct this or reprovision!") + + except KeyError: + raise CommandError("Could not retrieve the actual domain, forest level and/or lowest DC function level!") + + if subcommand == "show": + self.message("Domain and forest function level for domain '" + domain_dn + "'") + if level_forest < DS_DOMAIN_FUNCTION_2003: + self.message("\nATTENTION: You run SAMBA 4 on a forest function level lower than Windows 2003 (Native). This isn't supported! Please raise!") + if level_domain < DS_DOMAIN_FUNCTION_2003: + self.message("\nATTENTION: You run SAMBA 4 on a domain function level lower than Windows 2003 (Native). This isn't supported! Please raise!") + if min_level_dc < DS_DC_FUNCTION_2003: + self.message("\nATTENTION: You run SAMBA 4 on a lowest function level of a DC lower than Windows 2003. This isn't supported! Please step-up or upgrade the concerning DC(s)!") + + self.message("") + + if level_forest == DS_DOMAIN_FUNCTION_2000: + outstr = "2000" + elif level_forest == DS_DOMAIN_FUNCTION_2003_MIXED: + outstr = "2003 with mixed domains/interim (NT4 DC support)" + elif level_forest == DS_DOMAIN_FUNCTION_2003: + outstr = "2003" + elif level_forest == DS_DOMAIN_FUNCTION_2008: + outstr = "2008" + elif level_forest == DS_DOMAIN_FUNCTION_2008_R2: + outstr = "2008 R2" + else: + outstr = "higher than 2008 R2" + self.message("Forest function level: (Windows) " + outstr) + + if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0: + outstr = "2000 mixed (NT4 DC support)" + elif level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed == 0: + outstr = "2000" + elif level_domain == DS_DOMAIN_FUNCTION_2003_MIXED: + outstr = "2003 with mixed domains/interim (NT4 DC support)" + elif level_domain == DS_DOMAIN_FUNCTION_2003: + outstr = "2003" + elif level_domain == DS_DOMAIN_FUNCTION_2008: + outstr = "2008" + elif level_domain == DS_DOMAIN_FUNCTION_2008_R2: + outstr = "2008 R2" + else: + outstr = "higher than 2008 R2" + self.message("Domain function level: (Windows) " + outstr) + + if min_level_dc == DS_DC_FUNCTION_2000: + outstr = "2000" + elif min_level_dc == DS_DC_FUNCTION_2003: + outstr = "2003" + elif min_level_dc == DS_DC_FUNCTION_2008: + outstr = "2008" + elif min_level_dc == DS_DC_FUNCTION_2008_R2: + outstr = "2008 R2" + else: + outstr = "higher than 2008 R2" + self.message("Lowest function level of a DC: (Windows) " + outstr) + + elif subcommand == "raise": + msgs = [] + + if domain is not None: + if domain == "2003": + new_level_domain = DS_DOMAIN_FUNCTION_2003 + elif domain == "2008": + new_level_domain = DS_DOMAIN_FUNCTION_2008 + elif domain == "2008_R2": + new_level_domain = DS_DOMAIN_FUNCTION_2008_R2 + + if new_level_domain <= level_domain and level_domain_mixed == 0: + raise CommandError("Domain function level can't be smaller equal to the actual one!") + + if new_level_domain > min_level_dc: + raise CommandError("Domain function level can't be higher than the lowest function level of a DC!") + + # Deactivate mixed/interim domain support + if level_domain_mixed != 0: + m = ldb.Message() + m.dn = ldb.Dn(samdb, domain_dn) + m["nTMixedDomain"] = ldb.MessageElement("0", + ldb.FLAG_MOD_REPLACE, "nTMixedDomain") + samdb.modify(m) + m = ldb.Message() + m.dn = ldb.Dn(samdb, domain_dn) + m["msDS-Behavior-Version"]= ldb.MessageElement( + str(new_level_domain), ldb.FLAG_MOD_REPLACE, + "msDS-Behavior-Version") + samdb.modify(m) + level_domain = new_level_domain + msgs.append("Domain function level changed!") + + if forest is not None: + if forest == "2003": + new_level_forest = DS_DOMAIN_FUNCTION_2003 + elif forest == "2008": + new_level_forest = DS_DOMAIN_FUNCTION_2008 + elif forest == "2008_R2": + new_level_forest = DS_DOMAIN_FUNCTION_2008_R2 + if new_level_forest <= level_forest: + raise CommandError("Forest function level can't be smaller equal to the actual one!") + if new_level_forest > level_domain: + raise CommandError("Forest function level can't be higher than the domain function level(s). Please raise it/them first!") + m = ldb.Message() + m.dn = ldb.Dn(samdb, "CN=Partitions,CN=Configuration," + + domain_dn) + m["msDS-Behavior-Version"]= ldb.MessageElement( + str(new_level_forest), ldb.FLAG_MOD_REPLACE, + "msDS-Behavior-Version") + samdb.modify(m) + msgs.append("Forest function level changed!") + msgs.append("All changes applied successfully!") + self.message("\n".join(msgs)) + else: + raise CommandError("Wrong argument '%s'!" % subcommand) diff --git a/source4/scripting/python/samba/netcmd/pwsettings.py b/source4/scripting/python/samba/netcmd/pwsettings.py old mode 100755 new mode 100644 index 724c28e5f9..0568ea78e6 --- a/source4/scripting/python/samba/netcmd/pwsettings.py +++ b/source4/scripting/python/samba/netcmd/pwsettings.py @@ -42,11 +42,11 @@ class cmd_pwsettings(Command): synopsis = "(show | set )" - takes_optiongroups = [ - options.SambaOptions, - options.VersionOptions, - options.CredentialsOptions, - ] + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptions, + } takes_options = [ Option("-H", help="LDB URL for database or target server", type=str), @@ -63,10 +63,12 @@ class cmd_pwsettings(Command): help="The maximum password age ( | default). Default is 43.", type=str), ] - def run(self, H=None, min_pwd_age=None, max_pwd_age=None, quiet=False, - complexity=None, history_length=None, min_pwd_length=None, - username=None, simple_bind_dn=None, no_pass=None, workgroup=None, - kerberos=None, configfile=None, password=None): + takes_args = ["subcommand"] + + def run(self, subcommand, H=None, min_pwd_age=None, max_pwd_age=None, + quiet=False, complexity=None, history_length=None, + min_pwd_length=None, credopts=None, sambaopts=None, + versionopts=None): lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp) @@ -75,12 +77,13 @@ class cmd_pwsettings(Command): else: url = lp.get("sam database") - samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp) + samdb = SamDB(url=url, session_info=system_session(), + credentials=creds, lp=lp) domain_dn = SamDB.domain_dn(samdb) res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE, - attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength", "minPwdAge", - "maxPwdAge"]) + attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength", + "minPwdAge", "maxPwdAge"]) assert(len(res) == 1) try: pwd_props = int(res[0]["pwdProperties"][0]) @@ -92,7 +95,7 @@ class cmd_pwsettings(Command): except KeyError: raise CommandError("Could not retrieve password properties!") - if args[0] == "show": + if subcommand == "show": self.message("Password informations for domain '%s'" % domain_dn) self.message("") if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0: @@ -103,7 +106,7 @@ class cmd_pwsettings(Command): self.message("Minimum password length: %d" % min_pwd_len) self.message("Minimum password age (days): %d" % min_pwd_age) self.message("Maximum password age (days): %d" % max_pwd_age) - elif args[0] == "set": + elif subcommand == "set": msgs = [] m = ldb.Message() m.dn = ldb.Dn(samdb, domain_dn) @@ -184,4 +187,4 @@ class cmd_pwsettings(Command): msgs.append("All changes applied successfully!") self.message("\n".join(msgs)) else: - raise CommandError("Wrong argument '" + args[0] + "'!") + raise CommandError("Wrong argument '%s'!" % subcommand) diff --git a/source4/setup/domainlevel b/source4/setup/domainlevel deleted file mode 100755 index c37d811dd8..0000000000 --- a/source4/setup/domainlevel +++ /dev/null @@ -1,250 +0,0 @@ -#!/usr/bin/python -# -# Raises domain and forest function levels -# -# Copyright Matthias Dieter Wallnoefer 2009 -# -# 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 3 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, see . -# - -# Notice: At the moment we have some more checks to do here on the special -# attributes (consider attribute "msDS-Behavior-Version). This is due to the -# fact that we on s4 LDB don't implement their change policy (only certain -# values, only increments possible...) yet. - -import sys - -# Find right directory when running from source tree -sys.path.insert(0, "bin/python") - -import samba.getopt as options -import optparse -import ldb - -from samba.auth import system_session -from samba.samdb import SamDB -from samba import DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2003 -from samba import DS_DOMAIN_FUNCTION_2003_MIXED, DS_DOMAIN_FUNCTION_2008 -from samba import DS_DOMAIN_FUNCTION_2008_R2 -from samba import DS_DC_FUNCTION_2000, DS_DC_FUNCTION_2003, DS_DC_FUNCTION_2008 -from samba import DS_DC_FUNCTION_2008_R2 - -parser = optparse.OptionParser("domainlevel (show | raise )") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) -parser.add_option_group(options.VersionOptions(parser)) -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) -parser.add_option("-H", help="LDB URL for database or target server", type=str) -parser.add_option("--quiet", help="Be quiet", action="store_true") -parser.add_option("--forest", type="choice", - choices=["2003", "2008", "2008_R2"], - help="The forest function level (2003 | 2008 | 2008_R2)") -parser.add_option("--domain", type="choice", - choices=["2003", "2008", "2008_R2"], - help="The domain function level (2003 | 2008 | 2008_R2)") -opts, args = parser.parse_args() - -# -# print a message if quiet is not set -# -def message(text): - if not opts.quiet: - print text - -if len(args) == 0: - parser.print_usage() - sys.exit(1) - -lp = sambaopts.get_loadparm() -creds = credopts.get_credentials(lp) - -if opts.H is not None: - url = opts.H -else: - url = lp.get("sam database") - -samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp) - -domain_dn = SamDB.domain_dn(samdb) - -res_forest = samdb.search("CN=Partitions,CN=Configuration," + domain_dn, - scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"]) -assert(len(res_forest) == 1) - -res_domain = samdb.search(domain_dn, scope=ldb.SCOPE_BASE, - attrs=["msDS-Behavior-Version", "nTMixedDomain"]) -assert(len(res_domain) == 1) - -res_dc_s = samdb.search("CN=Sites,CN=Configuration," + domain_dn, - scope=ldb.SCOPE_SUBTREE, expression="(objectClass=nTDSDSA)", - attrs=["msDS-Behavior-Version"]) -assert(len(res_dc_s) >= 1) - -try: - level_forest = int(res_forest[0]["msDS-Behavior-Version"][0]) - level_domain = int(res_domain[0]["msDS-Behavior-Version"][0]) - level_domain_mixed = int(res_domain[0]["nTMixedDomain"][0]) - - min_level_dc = int(res_dc_s[0]["msDS-Behavior-Version"][0]) # Init value - for msg in res_dc_s: - if int(msg["msDS-Behavior-Version"][0]) < min_level_dc: - min_level_dc = int(msg["msDS-Behavior-Version"][0]) - - if level_forest < 0 or level_domain < 0: - print >>sys.stderr, "ERROR: Domain and/or forest function level(s) is/are invalid. Correct them or reprovision!" - sys.exit(1) - if min_level_dc < 0: - print >>sys.stderr, "ERROR: Lowest function level of a DC is invalid. Correct this or reprovision!" - sys.exit(1) - if level_forest > level_domain: - print >>sys.stderr, "ERROR: Forest function level is higher than the domain level(s). Correct this or reprovision!" - sys.exit(1) - if level_domain > min_level_dc: - print >>sys.stderr, "ERROR: Domain function level is higher than the lowest function level of a DC. Correct this or reprovision!" - sys.exit(1) - -except KeyError: - print >>sys.stderr, "ERROR: Could not retrieve the actual domain, forest level and/or lowest DC function level!" - if args[0] == "show": - print >>sys.stderr, "So the levels can't be displayed!" - sys.exit(1) - -if args[0] == "show": - message("Domain and forest function level for domain '" + domain_dn + "'") - if level_forest < DS_DOMAIN_FUNCTION_2003: - message("\nATTENTION: You run SAMBA 4 on a forest function level lower than Windows 2003 (Native). This isn't supported! Please raise!") - if level_domain < DS_DOMAIN_FUNCTION_2003: - message("\nATTENTION: You run SAMBA 4 on a domain function level lower than Windows 2003 (Native). This isn't supported! Please raise!") - if min_level_dc < DS_DC_FUNCTION_2003: - message("\nATTENTION: You run SAMBA 4 on a lowest function level of a DC lower than Windows 2003. This isn't supported! Please step-up or upgrade the concerning DC(s)!") - - message("") - - if level_forest == DS_DOMAIN_FUNCTION_2000: - outstr = "2000" - elif level_forest == DS_DOMAIN_FUNCTION_2003_MIXED: - outstr = "2003 with mixed domains/interim (NT4 DC support)" - elif level_forest == DS_DOMAIN_FUNCTION_2003: - outstr = "2003" - elif level_forest == DS_DOMAIN_FUNCTION_2008: - outstr = "2008" - elif level_forest == DS_DOMAIN_FUNCTION_2008_R2: - outstr = "2008 R2" - else: - outstr = "higher than 2008 R2" - message("Forest function level: (Windows) " + outstr) - - if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0: - outstr = "2000 mixed (NT4 DC support)" - elif level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed == 0: - outstr = "2000" - elif level_domain == DS_DOMAIN_FUNCTION_2003_MIXED: - outstr = "2003 with mixed domains/interim (NT4 DC support)" - elif level_domain == DS_DOMAIN_FUNCTION_2003: - outstr = "2003" - elif level_domain == DS_DOMAIN_FUNCTION_2008: - outstr = "2008" - elif level_domain == DS_DOMAIN_FUNCTION_2008_R2: - outstr = "2008 R2" - else: - outstr = "higher than 2008 R2" - message("Domain function level: (Windows) " + outstr) - - if min_level_dc == DS_DC_FUNCTION_2000: - outstr = "2000" - elif min_level_dc == DS_DC_FUNCTION_2003: - outstr = "2003" - elif min_level_dc == DS_DC_FUNCTION_2008: - outstr = "2008" - elif min_level_dc == DS_DC_FUNCTION_2008_R2: - outstr = "2008 R2" - else: - outstr = "higher than 2008 R2" - message("Lowest function level of a DC: (Windows) " + outstr) - -elif args[0] == "raise": - msgs = [] - - if opts.domain is not None: - arg = opts.domain - - if arg == "2003": - new_level_domain = DS_DOMAIN_FUNCTION_2003 - elif arg == "2008": - new_level_domain = DS_DOMAIN_FUNCTION_2008 - elif arg == "2008_R2": - new_level_domain = DS_DOMAIN_FUNCTION_2008_R2 - - if new_level_domain <= level_domain and level_domain_mixed == 0: - print >>sys.stderr, "ERROR: Domain function level can't be smaller equal to the actual one!" - sys.exit(1) - - if new_level_domain > min_level_dc: - print >>sys.stderr, "ERROR: Domain function level can't be higher than the lowest function level of a DC!" - sys.exit(1) - - # Deactivate mixed/interim domain support - if level_domain_mixed != 0: - m = ldb.Message() - m.dn = ldb.Dn(samdb, domain_dn) - m["nTMixedDomain"] = ldb.MessageElement("0", - ldb.FLAG_MOD_REPLACE, "nTMixedDomain") - samdb.modify(m) - - m = ldb.Message() - m.dn = ldb.Dn(samdb, domain_dn) - m["msDS-Behavior-Version"]= ldb.MessageElement( - str(new_level_domain), ldb.FLAG_MOD_REPLACE, - "msDS-Behavior-Version") - samdb.modify(m) - - level_domain = new_level_domain - - msgs.append("Domain function level changed!") - - if opts.forest is not None: - arg = opts.forest - - if arg == "2003": - new_level_forest = DS_DOMAIN_FUNCTION_2003 - elif arg == "2008": - new_level_forest = DS_DOMAIN_FUNCTION_2008 - elif arg == "2008_R2": - new_level_forest = DS_DOMAIN_FUNCTION_2008_R2 - - if new_level_forest <= level_forest: - print >>sys.stderr, "ERROR: Forest function level can't be smaller equal to the actual one!" - sys.exit(1) - - if new_level_forest > level_domain: - print >>sys.stderr, "ERROR: Forest function level can't be higher than the domain function level(s). Please raise it/them first!" - sys.exit(1) - - m = ldb.Message() - m.dn = ldb.Dn(samdb, "CN=Partitions,CN=Configuration," - + domain_dn) - m["msDS-Behavior-Version"]= ldb.MessageElement( - str(new_level_forest), ldb.FLAG_MOD_REPLACE, - "msDS-Behavior-Version") - samdb.modify(m) - - msgs.append("Forest function level changed!") - - msgs.append("All changes applied successfully!") - - message("\n".join(msgs)) -else: - print >>sys.stderr, "ERROR: Wrong argument '" + args[0] + "'!" - sys.exit(1) -- cgit From 433f58f5a7490ba470dddc55e37325bb73cdba5c Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 20:37:48 +0100 Subject: s4/net: Pass all arguments through to the Python commands. --- source4/script/installmisc.sh | 2 +- source4/scripting/python/samba/netcmd/__init__.py | 11 +++++----- source4/utils/net/net.c | 26 ++++++++++++----------- 3 files changed, 21 insertions(+), 18 deletions(-) (limited to 'source4') diff --git a/source4/script/installmisc.sh b/source4/script/installmisc.sh index 31ca7e645d..1617ff7948 100755 --- a/source4/script/installmisc.sh +++ b/source4/script/installmisc.sh @@ -49,7 +49,7 @@ cp setup/ad-schema/*.txt $SETUPDIR/ad-schema || exit 1 cp setup/display-specifiers/*.txt $SETUPDIR/display-specifiers || exit 1 echo "Installing sbin scripts from setup/*" -for p in domainlevel enableaccount newuser provision setexpiry setpassword +for p in enableaccount newuser provision setexpiry setpassword do cp setup/$p $SBINDIR || exit 1 chmod a+x $SBINDIR/$p diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index 5c18d29fc3..cb8fa01fe1 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -19,6 +19,7 @@ import optparse from samba import getopt as options, Ldb +import sys class Option(optparse.Option): @@ -82,7 +83,11 @@ class Command(object): if len(args) < len(self.takes_args): self.usage(args) return -1 - return self.run(*args, **kwargs) + try: + return self.run(*args, **kwargs) + except CommandError, e: + print >>sys.stderr, "ERROR: %s" % e + return -1 def run(self): """Run the command. This should be overriden by all subclasses.""" @@ -97,11 +102,7 @@ class SuperCommand(Command): def run(self, subcommand, *args, **kwargs): if not subcommand in subcommands: print >>sys.stderr, "ERROR: No such subcommand '%s'" % subcommand - try: return subcommands[subcommand].run(*args, **kwargs) - except CommandError, e: - print >>sys.stderr, "ERROR: %s" % e.message - return -1 def usage(self, subcommand=None, *args, **kwargs): if subcommand is None: diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c index 9725402c7f..7b8f092f93 100644 --- a/source4/utils/net/net.c +++ b/source4/utils/net/net.c @@ -130,7 +130,6 @@ int net_run_function(struct net_context *ctx, int (*usage_fn)(struct net_context *ctx, int argc, const char **argv)) { int i; - PyObject *py_cmds, *py_cmd; if (argc == 0) { return usage_fn(ctx, argc, argv); @@ -144,17 +143,6 @@ int net_run_function(struct net_context *ctx, return functable[i].fn(ctx, argc-1, argv+1); } - py_cmds = py_commands(); - if (py_cmds == NULL) { - return 1; - } - - py_cmd = PyDict_GetItemString(py_cmds, argv[0]); - if (py_cmd != NULL) { - return py_call_with_string_args(py_cmd, "_run", - argc-1, argv+1); - } - d_printf("No command: %s\n", argv[0]); return usage_fn(ctx, argc, argv); } @@ -288,6 +276,7 @@ static int binary_net(int argc, const char **argv) int opt,i; int rc; int argc_new; + PyObject *py_cmds, *py_cmd; const char **argv_new; struct tevent_context *ev; struct net_context *ctx = NULL; @@ -352,6 +341,19 @@ static int binary_net(int argc, const char **argv) Py_Initialize(); py_update_path("bin"); /* FIXME: Can't assume this is always the case */ + py_cmds = py_commands(); + if (py_cmds == NULL) { + return 1; + } + + py_cmd = PyDict_GetItemString(py_cmds, argv[1]); + if (py_cmd != NULL) { + rc = py_call_with_string_args(py_cmd, "_run", + argc-2, argv+2); + talloc_free(ev); + return rc; + } + rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable, net_usage); -- cgit From e2c4d8281d726716a00cfe2e3e0352777fc8b66f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 28 Dec 2009 21:07:25 +0100 Subject: s4/net: Allow options before arguments for Python commands. --- source4/scripting/python/samba/netcmd/__init__.py | 3 ++- source4/utils/net/net.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index cb8fa01fe1..1a04210f95 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -75,12 +75,13 @@ class Command(object): parser, optiongroups = self._create_parser() opts, args = parser.parse_args(list(argv)) # Filter out options from option groups + args = args[1:] kwargs = dict(opts.__dict__) for option_group in parser.option_groups: for option in option_group.option_list: del kwargs[option.dest] kwargs.update(optiongroups) - if len(args) < len(self.takes_args): + if len(args) != len(self.takes_args): self.usage(args) return -1 try: diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c index 7b8f092f93..f761ef4050 100644 --- a/source4/utils/net/net.c +++ b/source4/utils/net/net.c @@ -346,10 +346,10 @@ static int binary_net(int argc, const char **argv) return 1; } - py_cmd = PyDict_GetItemString(py_cmds, argv[1]); + py_cmd = PyDict_GetItemString(py_cmds, argv_new[1]); if (py_cmd != NULL) { rc = py_call_with_string_args(py_cmd, "_run", - argc-2, argv+2); + argc-1, argv+1); talloc_free(ev); return rc; } -- cgit From 588b3e61812978f73d2708ec37da30726ac8026e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 29 Dec 2009 16:07:54 +0100 Subject: python: When updating sys.path to include the Samba python path, avoid throwing away the changes made by site.py. --- source4/scripting/python/modules.c | 43 +++++++++++++++++++++++++++++++++++--- source4/scripting/python/modules.h | 2 +- 2 files changed, 41 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/modules.c b/source4/scripting/python/modules.c index 5365c5007d..198b3ccf12 100644 --- a/source4/scripting/python/modules.c +++ b/source4/scripting/python/modules.c @@ -61,10 +61,47 @@ void py_load_samba_modules(void) } } -void py_update_path(const char *bindir) +static bool PySys_PathPrepend(PyObject *list, const char *path) +{ + PyObject *py_path = PyString_FromString(path); + if (py_path == NULL) + return false; + + return (PyList_Insert(list, 0, py_path) == 0); +} + +bool py_update_path(const char *bindir) { char *newpath; - asprintf(&newpath, "%s/python:%s/../scripting/python:%s", bindir, bindir, Py_GetPath()); - PySys_SetPath(newpath); + PyObject *mod_sys, *py_path; + + mod_sys = PyImport_ImportModule("sys"); + if (mod_sys == NULL) { + return false; + } + + py_path = PyObject_GetAttrString(mod_sys, "path"); + if (py_path == NULL) { + return false; + } + + if (!PyList_Check(py_path)) { + return false; + } + + asprintf(&newpath, "%s/../scripting/python", bindir); + if (!PySys_PathPrepend(py_path, newpath)) { + free(newpath); + return false; + } free(newpath); + + asprintf(&newpath, "%s/python", bindir); + if (!PySys_PathPrepend(py_path, newpath)) { + free(newpath); + return false; + } + free(newpath); + + return true; } diff --git a/source4/scripting/python/modules.h b/source4/scripting/python/modules.h index 6b242ee257..4d1067cdd4 100644 --- a/source4/scripting/python/modules.h +++ b/source4/scripting/python/modules.h @@ -21,7 +21,7 @@ #define __SAMBA_PYTHON_MODULES_H__ void py_load_samba_modules(void); -void py_update_path(const char *bindir); +bool py_update_path(const char *bindir); #define py_iconv_convenience(mem_ctx) smb_iconv_convenience_init(mem_ctx, "ASCII", PyUnicode_GetDefaultEncoding(), true) -- cgit From 94454ad07393e1fea0b04ede96fe95893ed2d00e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 29 Dec 2009 16:08:17 +0100 Subject: net: Make arguments available to python commands as sys.argv. --- source4/utils/net/net.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4') diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c index f761ef4050..68fee9709f 100644 --- a/source4/utils/net/net.c +++ b/source4/utils/net/net.c @@ -339,6 +339,7 @@ static int binary_net(int argc, const char **argv) py_load_samba_modules(); Py_Initialize(); + PySys_SetArgv(argc, argv); py_update_path("bin"); /* FIXME: Can't assume this is always the case */ py_cmds = py_commands(); -- cgit From fbb59b2dcac1ce4d952c17d010ebf3bcfca863cd Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 29 Dec 2009 16:08:44 +0100 Subject: dsdb: Fix dependencies when building against system ldb. --- source4/auth/credentials/config.mk | 2 +- source4/dsdb/config.mk | 4 ++-- source4/dsdb/samdb/ldb_modules/config.mk | 17 +++++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'source4') diff --git a/source4/auth/credentials/config.mk b/source4/auth/credentials/config.mk index 6b051ef46c..32f415a8bf 100644 --- a/source4/auth/credentials/config.mk +++ b/source4/auth/credentials/config.mk @@ -4,7 +4,7 @@ PUBLIC_DEPENDENCIES = \ LIBCLI_AUTH SECRETS LIBCRYPTO KERBEROS UTIL_LDB HEIMDAL_GSSAPI PRIVATE_DEPENDENCIES = \ - SECRETS + SECRETS SAMDB CREDENTIALS_OBJ_FILES = $(addprefix $(authsrcdir)/credentials/, credentials.o credentials_files.o credentials_ntlm.o credentials_krb5.o ../kerberos/kerberos_util.o) diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index dfc5def64e..c5d1c24e04 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -22,7 +22,7 @@ $(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/samdb_proto.h,$(SAMDB_OB # PUBLIC_HEADERS += dsdb/samdb/samdb.h [SUBSYSTEM::SAMDB_COMMON] -PRIVATE_DEPENDENCIES = LIBLDB +PRIVATE_DEPENDENCIES = LIBLDB NDR_DRSBLOBS LIBCLI_LDAP_NDR UTIL_LDB LIBCLI_AUTH SAMDB_COMMON_OBJ_FILES = $(addprefix $(dsdbsrcdir)/common/, \ util.o \ @@ -31,7 +31,7 @@ SAMDB_COMMON_OBJ_FILES = $(addprefix $(dsdbsrcdir)/common/, \ $(eval $(call proto_header_template,$(dsdbsrcdir)/common/proto.h,$(SAMDB_COMMON_OBJ_FILES:.o=.c))) [SUBSYSTEM::SAMDB_SCHEMA] -PRIVATE_DEPENDENCIES = SAMDB_COMMON NDR_DRSUAPI NDR_DRSBLOBS +PRIVATE_DEPENDENCIES = SAMDB_COMMON NDR_DRSUAPI NDR_DRSBLOBS LDBSAMBA SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \ schema_init.o \ diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index 3bd38606ea..6128dc9d65 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -1,7 +1,7 @@ ################################################ # Start SUBSYSTEM DSDB_MODULE_HELPERS [SUBSYSTEM::DSDB_MODULE_HELPERS] -PRIVATE_DEPENDENCIES = LIBLDB +PRIVATE_DEPENDENCIES = LIBLDB LIBNDR SAMDB_SCHEMA DSDB_MODULE_HELPERS_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/util.o @@ -12,7 +12,7 @@ $(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/ldb_modules/util_proto.h # Start MODULE ldb_samba_dsdb [MODULE::ldb_samba_dsdb] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS LIBNDR +PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS LIBNDR DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(samba_dsdb) # End MODULE ldb_samba_dsdb ################################################ @@ -119,7 +119,7 @@ ldb_pdc_fsmo_OBJ_FILES = \ # Start MODULE ldb_samldb [MODULE::ldb_samldb] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LDAP_ENCODE SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LDAP_ENCODE SAMDB DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(samldb) # # End MODULE ldb_samldb @@ -242,7 +242,7 @@ ldb_extended_dn_out_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/extended_dn_out. # Start MODULE ldb_extended_dn_store [MODULE::ldb_extended_dn_store] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL SAMDB DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(extended_dn_store) # End MODULE ldb_extended_dn_store ################################################ @@ -301,7 +301,7 @@ ldb_update_keytab_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/update_keytab.o [MODULE::ldb_objectclass] INIT_FUNCTION = LDB_MODULE(objectclass) CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB DSDB_MODULE_HELPERS LIBSAMBA-UTIL SUBSYSTEM = LIBLDB # End MODULE ldb_objectclass ################################################ @@ -325,7 +325,7 @@ ldb_subtree_rename_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/subtree_rename.o [MODULE::ldb_subtree_delete] INIT_FUNCTION = LDB_MODULE(subtree_delete) CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL DSDB_MODULE_HELPERS SUBSYSTEM = LIBLDB # End MODULE ldb_subtree_rename ################################################ @@ -385,7 +385,7 @@ ldb_instancetype_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/instancetype.o [MODULE::ldb_operational] SUBSYSTEM = LIBLDB CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT +PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT LIBSAMBA-UTIL SAMDB_COMMON DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(operational) # End MODULE ldb_operational ################################################ @@ -397,7 +397,8 @@ ldb_operational_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/operational.o [MODULE::ldb_descriptor] INIT_FUNCTION = LDB_MODULE(descriptor) CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB \ + DSDB_MODULE_HELPERS SUBSYSTEM = LIBLDB # End MODULE ldb_descriptor ################################################ -- cgit From a8e61ac084fc84fe9b1246ab97f0ca34cd9a0e8a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 10:44:19 +0100 Subject: s4:auth/ntlmssp: let get_challenge() return a NTSTATUS and fill a stack buffer metze --- source4/auth/ntlmssp/ntlmssp.h | 3 ++- source4/auth/ntlmssp/ntlmssp_server.c | 23 +++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp.h b/source4/auth/ntlmssp/ntlmssp.h index f596cb81ee..3354af9dbf 100644 --- a/source4/auth/ntlmssp/ntlmssp.h +++ b/source4/auth/ntlmssp/ntlmssp.h @@ -81,7 +81,8 @@ struct gensec_ntlmssp_state * @return 8 bytes of challenge data, determined by the server to be the challenge for NTLM authentication * */ - const uint8_t *(*get_challenge)(const struct gensec_ntlmssp_state *); + NTSTATUS (*get_challenge)(const struct gensec_ntlmssp_state *, + uint8_t challenge[8]); /** * Callback to find if the challenge used by NTLM authentication may be modified diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index 281ffbfa6d..ae19970044 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -124,8 +124,9 @@ NTSTATUS ntlmssp_server_negotiate(struct gensec_security *gensec_security, DATA_BLOB struct_blob; uint32_t neg_flags = 0; uint32_t ntlmssp_command, chal_flags; - const uint8_t *cryptkey; + uint8_t cryptkey[8]; const char *target_name; + NTSTATUS status; /* parse the NTLMSSP packet */ #if 0 @@ -150,10 +151,11 @@ NTSTATUS ntlmssp_server_negotiate(struct gensec_security *gensec_security, ntlmssp_handle_neg_flags(gensec_ntlmssp_state, neg_flags, gensec_ntlmssp_state->allow_lm_key); /* Ask our caller what challenge they would like in the packet */ - cryptkey = gensec_ntlmssp_state->get_challenge(gensec_ntlmssp_state); - if (!cryptkey) { - DEBUG(1, ("ntlmssp_server_negotiate: backend doesn't give a challenge\n")); - return NT_STATUS_INTERNAL_ERROR; + status = gensec_ntlmssp_state->get_challenge(gensec_ntlmssp_state, cryptkey); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("ntlmssp_server_negotiate: backend doesn't give a challenge: %s\n", + nt_errstr(status))); + return status; } /* Check if we may set the challenge */ @@ -597,22 +599,19 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, * @return an 8 byte random challenge */ -static const uint8_t *auth_ntlmssp_get_challenge(const struct gensec_ntlmssp_state *gensec_ntlmssp_state) +static NTSTATUS auth_ntlmssp_get_challenge(const struct gensec_ntlmssp_state *gensec_ntlmssp_state, + uint8_t chal[8]) { NTSTATUS status; - uint8_t *chal = talloc_array(gensec_ntlmssp_state, uint8_t, 8); - if (!chal) { - return NULL; - } status = gensec_ntlmssp_state->auth_context->get_challenge(gensec_ntlmssp_state->auth_context, chal); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("auth_ntlmssp_get_challenge: failed to get challenge: %s\n", nt_errstr(status))); - return NULL; + return status; } - return chal; + return NT_STATUS_OK; } /** -- cgit From 60b9434492423d463bd1a43d84b5084dce980ecb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 13:53:44 +0100 Subject: s4:ntlmssp_server: remove unused variable metze --- source4/auth/ntlmssp/ntlmssp_server.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index ae19970044..80d5896b58 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -182,7 +182,6 @@ NTSTATUS ntlmssp_server_negotiate(struct gensec_security *gensec_security, /* This creates the 'blob' of names that appears at the end of the packet */ if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { char dnsdomname[MAXHOSTNAMELEN], dnsname[MAXHOSTNAMELEN]; - const char *target_name_dns = ""; /* Find out the DNS domain name */ dnsdomname[0] = '\0'; @@ -196,12 +195,6 @@ NTSTATUS ntlmssp_server_negotiate(struct gensec_security *gensec_security, } strlower_m(dnsname); - if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) { - target_name_dns = dnsdomname; - } else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) { - target_name_dns = dnsname; - } - msrpc_gen(out_mem_ctx, &struct_blob, "aaaaa", MsvAvNbDomainName, target_name, -- cgit From dea456089a7838219e7819bfb04a98e03f3d0002 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 12:58:44 +0100 Subject: s4:ntlmssp: use data_blob_null in ntlmssp_server_auth() metze --- source4/auth/ntlmssp/ntlmssp_server.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index 80d5896b58..7c165b8eea 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -543,8 +543,8 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, const DATA_BLOB in, DATA_BLOB *out) { struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data; - DATA_BLOB user_session_key = data_blob(NULL, 0); - DATA_BLOB lm_session_key = data_blob(NULL, 0); + DATA_BLOB user_session_key = data_blob_null; + DATA_BLOB lm_session_key = data_blob_null; NTSTATUS nt_status; TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx); @@ -553,7 +553,7 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, } /* zero the outbound NTLMSSP packet */ - *out = data_blob_talloc(out_mem_ctx, NULL, 0); + *out = data_blob_null; if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_preauth(gensec_ntlmssp_state, in))) { talloc_free(mem_ctx); @@ -574,7 +574,9 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, talloc_free(mem_ctx); return nt_status; } - + + gensec_ntlmssp_state->session_key = data_blob_null; + if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL|GENSEC_FEATURE_SESSION_KEY)) { nt_status = ntlmssp_server_postauth(gensec_security, &user_session_key, &lm_session_key); -- cgit From 7d4692fa43fd84a8251231781fba7f3f9e46c30b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 15:54:59 +0100 Subject: s4:ntlmssp_server: clear session key in ntlmssp_server_preauth() metze --- source4/auth/ntlmssp/ntlmssp_server.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index 7c165b8eea..7514b3234a 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -263,6 +263,7 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_ntlmssp_state *gensec_ntlms } /* zero these out */ + data_blob_free(&gensec_ntlmssp_state->session_key); data_blob_free(&gensec_ntlmssp_state->lm_resp); data_blob_free(&gensec_ntlmssp_state->nt_resp); data_blob_free(&gensec_ntlmssp_state->encrypted_session_key); @@ -575,15 +576,12 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, return nt_status; } - gensec_ntlmssp_state->session_key = data_blob_null; - if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL|GENSEC_FEATURE_SESSION_KEY)) { nt_status = ntlmssp_server_postauth(gensec_security, &user_session_key, &lm_session_key); talloc_free(mem_ctx); return nt_status; } else { - gensec_ntlmssp_state->session_key = data_blob(NULL, 0); talloc_free(mem_ctx); return NT_STATUS_OK; } -- cgit From 3f04b60fb9051f65074316b7704793759f4cbdf7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 16:02:00 +0100 Subject: s4:ntlmssp_server: don't use mem_ctx in auth_ntlmssp_check_password() metze --- source4/auth/ntlmssp/ntlmssp_server.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index 7514b3234a..a6995aad8a 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -651,7 +651,9 @@ static NTSTATUS auth_ntlmssp_check_password(struct gensec_ntlmssp_state *gensec_ DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) { NTSTATUS nt_status; - struct auth_usersupplied_info *user_info = talloc(mem_ctx, struct auth_usersupplied_info); + struct auth_usersupplied_info *user_info; + + user_info = talloc(gensec_ntlmssp_state, struct auth_usersupplied_info); if (!user_info) { return NT_STATUS_NO_MEMORY; } @@ -670,31 +672,21 @@ static NTSTATUS auth_ntlmssp_check_password(struct gensec_ntlmssp_state *gensec_ user_info->password.response.nt = gensec_ntlmssp_state->nt_resp; user_info->password.response.nt.data = talloc_steal(user_info, gensec_ntlmssp_state->nt_resp.data); - nt_status = gensec_ntlmssp_state->auth_context->check_password(gensec_ntlmssp_state->auth_context, - mem_ctx, - user_info, + nt_status = gensec_ntlmssp_state->auth_context->check_password(gensec_ntlmssp_state->auth_context, + gensec_ntlmssp_state, + user_info, &gensec_ntlmssp_state->server_info); talloc_free(user_info); NT_STATUS_NOT_OK_RETURN(nt_status); - talloc_steal(gensec_ntlmssp_state, gensec_ntlmssp_state->server_info); - if (gensec_ntlmssp_state->server_info->user_session_key.length) { - DEBUG(10, ("Got NT session key of length %u\n", + DEBUG(10, ("Got NT session key of length %u\n", (unsigned)gensec_ntlmssp_state->server_info->user_session_key.length)); - if (!talloc_reference(mem_ctx, gensec_ntlmssp_state->server_info->user_session_key.data)) { - return NT_STATUS_NO_MEMORY; - } - *user_session_key = gensec_ntlmssp_state->server_info->user_session_key; } if (gensec_ntlmssp_state->server_info->lm_session_key.length) { - DEBUG(10, ("Got LM session key of length %u\n", + DEBUG(10, ("Got LM session key of length %u\n", (unsigned)gensec_ntlmssp_state->server_info->lm_session_key.length)); - if (!talloc_reference(mem_ctx, gensec_ntlmssp_state->server_info->lm_session_key.data)) { - return NT_STATUS_NO_MEMORY; - } - *lm_session_key = gensec_ntlmssp_state->server_info->lm_session_key; } return nt_status; -- cgit From 994d34b949cd68b692ca688f162652c924732e84 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 16:07:16 +0100 Subject: s4:ntlmssp_server: don't use a mem_ctx for ntlmssp_server_auth() metze --- source4/auth/ntlmssp/ntlmssp_server.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index a6995aad8a..559cca0733 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -548,16 +548,11 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, DATA_BLOB lm_session_key = data_blob_null; NTSTATUS nt_status; - TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx); - if (!mem_ctx) { - return NT_STATUS_NO_MEMORY; - } - /* zero the outbound NTLMSSP packet */ *out = data_blob_null; - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_preauth(gensec_ntlmssp_state, in))) { - talloc_free(mem_ctx); + nt_status = ntlmssp_server_preauth(gensec_ntlmssp_state, in); + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } @@ -569,20 +564,19 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, */ /* Finally, actually ask if the password is OK */ - - if (!NT_STATUS_IS_OK(nt_status = gensec_ntlmssp_state->check_password(gensec_ntlmssp_state, mem_ctx, - &user_session_key, &lm_session_key))) { - talloc_free(mem_ctx); + nt_status = gensec_ntlmssp_state->check_password(gensec_ntlmssp_state, + NULL, + &user_session_key, + &lm_session_key); + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL|GENSEC_FEATURE_SESSION_KEY)) { nt_status = ntlmssp_server_postauth(gensec_security, &user_session_key, &lm_session_key); - talloc_free(mem_ctx); return nt_status; } else { - talloc_free(mem_ctx); return NT_STATUS_OK; } } -- cgit From f31d144e70c632892ffc7d5177789947e821ad7e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 16:10:57 +0100 Subject: s4:ntlmssp_server: always call ntlmssp_server_postauth() and decide there if it's a noop metze --- source4/auth/ntlmssp/ntlmssp_server.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index 559cca0733..b456337806 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -402,6 +402,11 @@ static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security, NTSTATUS nt_status; DATA_BLOB session_key = data_blob(NULL, 0); + if (!(gensec_security->want_features + & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL|GENSEC_FEATURE_SESSION_KEY))) { + return NT_STATUS_OK; + } + if (user_session_key) dump_data_pw("USER session key:\n", user_session_key->data, user_session_key->length); @@ -572,13 +577,14 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, return nt_status; } - if (gensec_security->want_features - & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL|GENSEC_FEATURE_SESSION_KEY)) { - nt_status = ntlmssp_server_postauth(gensec_security, &user_session_key, &lm_session_key); + nt_status = ntlmssp_server_postauth(gensec_security, + &user_session_key, + &lm_session_key); + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; - } else { - return NT_STATUS_OK; } + + return NT_STATUS_OK; } /** -- cgit From d5cbfbb93a1718b3031f37a62e350a2cd7ab0bdc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 29 Dec 2009 16:14:05 +0100 Subject: s4:ntlmssp: remove mem_ctx from check_password() callback to match s3 metze --- source4/auth/ntlmssp/ntlmssp.h | 1 - source4/auth/ntlmssp/ntlmssp_server.c | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlmssp/ntlmssp.h b/source4/auth/ntlmssp/ntlmssp.h index 3354af9dbf..7bed54d6d8 100644 --- a/source4/auth/ntlmssp/ntlmssp.h +++ b/source4/auth/ntlmssp/ntlmssp.h @@ -118,7 +118,6 @@ struct gensec_ntlmssp_state * */ NTSTATUS (*check_password)(struct gensec_ntlmssp_state *, - TALLOC_CTX *mem_ctx, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key); const char *server_name; diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index b456337806..c49bf2fea7 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -570,7 +570,6 @@ NTSTATUS ntlmssp_server_auth(struct gensec_security *gensec_security, /* Finally, actually ask if the password is OK */ nt_status = gensec_ntlmssp_state->check_password(gensec_ntlmssp_state, - NULL, &user_session_key, &lm_session_key); if (!NT_STATUS_IS_OK(nt_status)) { @@ -646,9 +645,8 @@ static NTSTATUS auth_ntlmssp_set_challenge(struct gensec_ntlmssp_state *gensec_n * Return the session keys used on the connection. */ -static NTSTATUS auth_ntlmssp_check_password(struct gensec_ntlmssp_state *gensec_ntlmssp_state, - TALLOC_CTX *mem_ctx, - DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) +static NTSTATUS auth_ntlmssp_check_password(struct gensec_ntlmssp_state *gensec_ntlmssp_state, + DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) { NTSTATUS nt_status; struct auth_usersupplied_info *user_info; -- cgit From 1aed373b119b98bf767ab02ea14940d017ad3868 Mon Sep 17 00:00:00 2001 From: Matthias Dieter Wallnöfer Date: Wed, 30 Dec 2009 12:39:55 +0100 Subject: s4:lib/registry/util.c - Reintroduce "FIXME"s Jelmer suggested to put them in again. --- source4/lib/registry/util.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4') diff --git a/source4/lib/registry/util.c b/source4/lib/registry/util.c index f9ea2a1934..5d451df33a 100644 --- a/source4/lib/registry/util.c +++ b/source4/lib/registry/util.c @@ -89,6 +89,7 @@ _PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, /* FIXME: We don't support this yet */ break; default: + /* FIXME */ /* Other datatypes aren't supported -> return "NULL" */ break; } @@ -156,6 +157,7 @@ _PUBLIC_ bool reg_string_to_val(TALLOC_CTX *mem_ctx, /* FIXME: We don't support this yet */ return false; default: + /* FIXME */ /* Other datatypes aren't supported -> return no success */ return false; } -- cgit From 31cc963ba0adc043032ad2113b44a5d599fa07d5 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 14:55:07 +0100 Subject: net: Allow python subcommands to provide commands that are not recognized by net itself. Signed-off-by: Andrew Tridgell --- source4/utils/net/net.c | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'source4') diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c index 68fee9709f..ee5cdf8e1c 100644 --- a/source4/utils/net/net.c +++ b/source4/utils/net/net.c @@ -292,6 +292,33 @@ static int binary_net(int argc, const char **argv) setlinebuf(stdout); + dcerpc_init(cmdline_lp_ctx); + + ev = s4_event_context_init(NULL); + if (!ev) { + d_printf("Failed to create an event context\n"); + exit(1); + } + py_load_samba_modules(); + Py_Initialize(); + PySys_SetArgv(argc, argv); + py_update_path("bin"); /* FIXME: Can't assume this is always the case */ + + py_cmds = py_commands(); + if (py_cmds == NULL) { + return 1; + } + + if (argc > 1) { + py_cmd = PyDict_GetItemString(py_cmds, argv[1]); + if (py_cmd != NULL) { + rc = py_call_with_string_args(py_cmd, "_run", + argc-1, argv+1); + talloc_free(ev); + return rc; + } + } + pc = poptGetContext("net", argc, (const char **) argv, long_options, POPT_CONTEXT_KEEP_FIRST); @@ -319,13 +346,7 @@ static int binary_net(int argc, const char **argv) return net_usage(ctx, argc, argv); } - dcerpc_init(cmdline_lp_ctx); - ev = s4_event_context_init(NULL); - if (!ev) { - d_printf("Failed to create an event context\n"); - exit(1); - } ctx = talloc(ev, struct net_context); if (!ctx) { d_printf("Failed to talloc a net_context\n"); @@ -337,23 +358,7 @@ static int binary_net(int argc, const char **argv) ctx->credentials = cmdline_credentials; ctx->event_ctx = ev; - py_load_samba_modules(); - Py_Initialize(); - PySys_SetArgv(argc, argv); - py_update_path("bin"); /* FIXME: Can't assume this is always the case */ - - py_cmds = py_commands(); - if (py_cmds == NULL) { - return 1; - } - py_cmd = PyDict_GetItemString(py_cmds, argv_new[1]); - if (py_cmd != NULL) { - rc = py_call_with_string_args(py_cmd, "_run", - argc-1, argv+1); - talloc_free(ev); - return rc; - } rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable, net_usage); -- cgit From 552e65679df23f488ecee2c0d8555f5e0dad9166 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 18:01:24 +0100 Subject: net: Allow Python commands to return None instead of 0. Signed-off-by: Andrew Tridgell --- source4/utils/net/net.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c index ee5cdf8e1c..ba935b9986 100644 --- a/source4/utils/net/net.c +++ b/source4/utils/net/net.c @@ -94,7 +94,14 @@ static int py_call_with_string_args(PyObject *self, const char *method, int argc return 1; } - return PyInt_AsLong(ret); + if (ret == Py_None) { + return 0; + } else if (PyInt_Check(ret)) { + return PyInt_AsLong(ret); + } else { + fprintf(stderr, "Function return value type unexpected.\n"); + return -1; + } } static PyObject *py_commands(void) -- cgit From b531696a5b878beef9d0177eeb4939160d1a602e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 19:53:05 +0100 Subject: net: Move 'setpassword' to 'net setpassword'. Signed-off-by: Andrew Tridgell --- source4/scripting/python/samba/netcmd/__init__.py | 9 ++- .../scripting/python/samba/netcmd/pwsettings.py | 2 +- .../scripting/python/samba/netcmd/setpassword.py | 77 ++++++++++++++++++++++ source4/setup/setpassword | 74 --------------------- 4 files changed, 86 insertions(+), 76 deletions(-) create mode 100644 source4/scripting/python/samba/netcmd/setpassword.py delete mode 100755 source4/setup/setpassword (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index 1a04210f95..0086fa6f70 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -81,7 +81,12 @@ class Command(object): for option in option_group.option_list: del kwargs[option.dest] kwargs.update(optiongroups) - if len(args) != len(self.takes_args): + for i, arg in enumerate(self.takes_args): + if arg[-1] != "?": + if len(args) < i: + self.usage(args) + return -1 + if len(args) > len(self.takes_args): self.usage(args) return -1 try: @@ -126,3 +131,5 @@ from samba.netcmd.pwsettings import cmd_pwsettings commands["pwsettings"] = cmd_pwsettings() from samba.netcmd.domainlevel import cmd_domainlevel commands["domainlevel"] = cmd_domainlevel() +from samba.netcmd.setpassword import cmd_setpassword +commands["setpassword"] = cmd_setpassword() diff --git a/source4/scripting/python/samba/netcmd/pwsettings.py b/source4/scripting/python/samba/netcmd/pwsettings.py index 0568ea78e6..eb3bb65790 100644 --- a/source4/scripting/python/samba/netcmd/pwsettings.py +++ b/source4/scripting/python/samba/netcmd/pwsettings.py @@ -1,7 +1,7 @@ #!/usr/bin/python # # Sets password settings. -# (Password complexity, history length, minimum password length, the minimum +# (Password complexity, history length, minimum password length, the minimum # and maximum password age) on a Samba4 server # # Copyright Matthias Dieter Wallnoefer 2009 diff --git a/source4/scripting/python/samba/netcmd/setpassword.py b/source4/scripting/python/samba/netcmd/setpassword.py new file mode 100644 index 0000000000..6393e47414 --- /dev/null +++ b/source4/scripting/python/samba/netcmd/setpassword.py @@ -0,0 +1,77 @@ +#!/usr/bin/python +# +# Sets a user password on a Samba4 server +# Copyright Jelmer Vernooij 2008 +# +# Based on the original in EJS: +# Copyright Andrew Tridgell 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 3 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, see . +# + +import samba.getopt as options +from samba.netcmd import Command, CommandError, Option + +from getpass import getpass +from samba.auth import system_session +from samba.samdb import SamDB + +class cmd_setpassword(Command): + """Change the password of a user.""" + + synopsis = "setpassword [username] [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptions, + } + + takes_options = [ + Option("-H", help="LDB URL for database or target server", type=str), + Option("--filter", help="LDAP Filter to set password on", type=str), + Option("--newpassword", help="Set password", type=str), + Option("--must-change-at-next-login", + help="Force password to be changed on next login", + action="store_true"), + ] + + takes_args = ["username?"] + + def run(self, username=None, filter=None, credopts=None, sambaopts=None, + versionopts=None, H=None, newpassword=None, + must_change_at_next_login=None): + if filter is None and username is None: + raise CommandError("Either the username or '--filter' must be specified!") + + password = newpassword + if password is None: + password = getpass("New Password: ") + + if filter is None: + filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + if H is not None: + url = H + else: + url = lp.get("sam database") + + samdb = SamDB(url=url, session_info=system_session(), + credentials=creds, lp=lp) + + samdb.setpassword(filter, password, + force_password_change_at_next_login_req=must_change_at_next_login) diff --git a/source4/setup/setpassword b/source4/setup/setpassword deleted file mode 100755 index 57772be7a7..0000000000 --- a/source4/setup/setpassword +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/python -# -# Sets a user password on a Samba4 server -# Copyright Jelmer Vernooij 2008 -# -# Based on the original in EJS: -# Copyright Andrew Tridgell 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 3 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, see . -# - -import sys - -# Find right directory when running from source tree -sys.path.insert(0, "bin/python") - -import samba.getopt as options -import optparse - -from getpass import getpass -from samba.auth import system_session -from samba.samdb import SamDB - -parser = optparse.OptionParser("setpassword [username] [options]") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) -parser.add_option_group(options.VersionOptions(parser)) -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) -parser.add_option("-H", help="LDB URL for database or target server", type=str) -parser.add_option("--filter", help="LDAP Filter to set password on", type=str) -parser.add_option("--newpassword", help="Set password", type=str) -parser.add_option("--must-change-at-next-login", help="Force password to be changed on next login", action="store_true") - -opts, args = parser.parse_args() - -filter = opts.filter - -if (len(args) == 0) and (filter is None): - print "Either the username or '--filter' must be specified!" - parser.print_usage() - sys.exit(1) - -password = opts.newpassword; -if password is None: - password = getpass("New Password: ") - -if filter is None: - username = args[0] - filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) - -lp = sambaopts.get_loadparm() -creds = credopts.get_credentials(lp) - -if opts.H is not None: - url = opts.H -else: - url = lp.get("sam database") - -samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp) - -samdb.setpassword(filter, password, force_password_change_at_next_login_req=opts.must_change_at_next_login) - -- cgit From 345b25d059db27f96b00143f7617919233a78ba4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 20:00:12 +0100 Subject: net: Move setexpiry to 'net setexpiry' Signed-off-by: Andrew Tridgell --- source4/script/installmisc.sh | 2 +- source4/scripting/python/samba/netcmd/__init__.py | 2 + source4/scripting/python/samba/netcmd/setexpiry.py | 71 +++++++++++++++++++++ source4/setup/setexpiry | 72 ---------------------- 4 files changed, 74 insertions(+), 73 deletions(-) create mode 100644 source4/scripting/python/samba/netcmd/setexpiry.py delete mode 100755 source4/setup/setexpiry (limited to 'source4') diff --git a/source4/script/installmisc.sh b/source4/script/installmisc.sh index 1617ff7948..b0e575448b 100755 --- a/source4/script/installmisc.sh +++ b/source4/script/installmisc.sh @@ -49,7 +49,7 @@ cp setup/ad-schema/*.txt $SETUPDIR/ad-schema || exit 1 cp setup/display-specifiers/*.txt $SETUPDIR/display-specifiers || exit 1 echo "Installing sbin scripts from setup/*" -for p in enableaccount newuser provision setexpiry setpassword +for p in enableaccount newuser provision do cp setup/$p $SBINDIR || exit 1 chmod a+x $SBINDIR/$p diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index 0086fa6f70..ca5a8ddf24 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -133,3 +133,5 @@ from samba.netcmd.domainlevel import cmd_domainlevel commands["domainlevel"] = cmd_domainlevel() from samba.netcmd.setpassword import cmd_setpassword commands["setpassword"] = cmd_setpassword() +from samba.netcmd.setexpiry import cmd_setexpiry +commands["setexpiry"] = cmd_setexpiry() diff --git a/source4/scripting/python/samba/netcmd/setexpiry.py b/source4/scripting/python/samba/netcmd/setexpiry.py new file mode 100644 index 0000000000..51cf4c8c1a --- /dev/null +++ b/source4/scripting/python/samba/netcmd/setexpiry.py @@ -0,0 +1,71 @@ +#!/usr/bin/python +# +# Sets the user password expiry on a Samba4 server +# Copyright Jelmer Vernooij 2008 +# +# Based on the original in EJS: +# Copyright Andrew Tridgell 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 3 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, see . +# + +from samba.netcmd import Command, CommandError, Option + +import samba.getopt as options + +from samba.auth import system_session +from samba.samdb import SamDB + +class cmd_setexpiry(Command): + + synopsis = "setexpiry [username] [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptions, + } + + takes_options = [ + Option("-H", help="LDB URL for database or target server", type=str), + Option("--filter", help="LDAP Filter to set password on", type=str), + Option("--days", help="Days to expiry", type=int), + Option("--noexpiry", help="Password does never expire", action="store_true"), + ] + + takes_args = ["username?"] + + def run(self, username=None, sambaopts=None, credopts=None, + versionopts=None, H=None, filter=None, days=None, noexpiry=None): + if username is None and filter is None: + raise CommandError("Either the username or '--filter' must be specified!") + + if filter is None: + filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + if days is None: + days = 0 + + if H is not None: + url = H + else: + url = lp.get("sam database") + + samdb = SamDB(url=url, session_info=system_session(), + credentials=creds, lp=lp) + + samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry) diff --git a/source4/setup/setexpiry b/source4/setup/setexpiry deleted file mode 100755 index 2740326f2b..0000000000 --- a/source4/setup/setexpiry +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/python -# -# Sets the user password expiry on a Samba4 server -# Copyright Jelmer Vernooij 2008 -# -# Based on the original in EJS: -# Copyright Andrew Tridgell 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 3 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, see . -# - -import sys - -# Find right directory when running from source tree -sys.path.insert(0, "bin/python") - -import samba.getopt as options -import optparse - -from samba.auth import system_session -from samba.samdb import SamDB - -parser = optparse.OptionParser("setexpiry [username] [options]") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) -parser.add_option_group(options.VersionOptions(parser)) -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) -parser.add_option("-H", help="LDB URL for database or target server", type=str) -parser.add_option("--filter", help="LDAP Filter to set password on", type=str) -parser.add_option("--days", help="Days to expiry", type=int) -parser.add_option("--noexpiry", help="Password does never expire", action="store_true") - -opts, args = parser.parse_args() - -filter = opts.filter - -if (len(args) == 0) and (filter is None): - print "Either the username or '--filter' must be specified!" - parser.print_usage() - sys.exit(1) - -days = opts.days -if days is None: - days = 0 - -if filter is None: - username = args[0] - filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) - -lp = sambaopts.get_loadparm() -creds = credopts.get_credentials(lp) - -if opts.H is not None: - url = opts.H -else: - url = lp.get("sam database") - -samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp) - -samdb.setexpiry(filter, days*24*3600, no_expiry_req=opts.noexpiry) -- cgit From 73594c248f35a6ebbe391cc46b717aff14d393be Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 20:10:34 +0100 Subject: net: Fix tests and documentation of setexpiry. Signed-off-by: Andrew Tridgell --- source4/scripting/python/samba/netcmd/__init__.py | 2 + .../scripting/python/samba/netcmd/enableaccount.py | 65 ++++++++++++++++++++++ source4/scripting/python/samba/netcmd/setexpiry.py | 1 + source4/setup/enableaccount | 65 ---------------------- 4 files changed, 68 insertions(+), 65 deletions(-) create mode 100755 source4/scripting/python/samba/netcmd/enableaccount.py delete mode 100755 source4/setup/enableaccount (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index ca5a8ddf24..3213dd71b3 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -135,3 +135,5 @@ from samba.netcmd.setpassword import cmd_setpassword commands["setpassword"] = cmd_setpassword() from samba.netcmd.setexpiry import cmd_setexpiry commands["setexpiry"] = cmd_setexpiry() +from samba.netcmd.enableaccount import cmd_enableaccount +commands["enableaccount"] = cmd_enableaccount() diff --git a/source4/scripting/python/samba/netcmd/enableaccount.py b/source4/scripting/python/samba/netcmd/enableaccount.py new file mode 100755 index 0000000000..d4af0a84f1 --- /dev/null +++ b/source4/scripting/python/samba/netcmd/enableaccount.py @@ -0,0 +1,65 @@ +#!/usr/bin/python +# +# Enables an user account on a Samba4 server +# Copyright Jelmer Vernooij 2008 +# +# Based on the original in EJS: +# Copyright Andrew Tridgell 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 3 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, see . +# + +import samba.getopt as options + +from samba.auth import system_session +from samba.netcmd import Command, CommandError, Option +from samba.samdb import SamDB + +class cmd_enableaccount(Command): + """Enable an account.""" + + synopsis = "enableaccount [username] [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptions, + } + + takes_options = [ + Option("-H", help="LDB URL for database or target server", type=str), + Option("--filter", help="LDAP Filter to set password on", type=str), + ] + + takes_args = ["username?"] + + def run(self, username=None, sambaopts=None, credopts=None, + versionopts=None, filter=None, H=None): + if username is None and filter is None: + raise CommandError("Either the username or '--filter' must be specified!") + + if filter is None: + filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + if H is not None: + url = H + else: + url = lp.get("sam database") + + samdb = SamDB(url=url, session_info=system_session(), + credentials=creds, lp=lp) + samdb.enable_account(filter) diff --git a/source4/scripting/python/samba/netcmd/setexpiry.py b/source4/scripting/python/samba/netcmd/setexpiry.py index 51cf4c8c1a..0c5dc5afff 100644 --- a/source4/scripting/python/samba/netcmd/setexpiry.py +++ b/source4/scripting/python/samba/netcmd/setexpiry.py @@ -28,6 +28,7 @@ from samba.auth import system_session from samba.samdb import SamDB class cmd_setexpiry(Command): + """Set the expiration of a user account.""" synopsis = "setexpiry [username] [options]" diff --git a/source4/setup/enableaccount b/source4/setup/enableaccount deleted file mode 100755 index f8f727c1ee..0000000000 --- a/source4/setup/enableaccount +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/python -# -# Enables an user account on a Samba4 server -# Copyright Jelmer Vernooij 2008 -# -# Based on the original in EJS: -# Copyright Andrew Tridgell 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 3 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, see . -# - -import sys - -sys.path.insert(0, "bin/python") - -import samba.getopt as options -import optparse - -from samba.auth import system_session -from samba.samdb import SamDB - -parser = optparse.OptionParser("enableaccount [username] [options]") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) -parser.add_option_group(options.VersionOptions(parser)) -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) -parser.add_option("-H", help="LDB URL for database or target server", type=str) -parser.add_option("--filter", help="LDAP Filter to set password on", type=str) - -opts, args = parser.parse_args() - -filter = opts.filter - -if (len(args) == 0) and (filter is None): - print "Either the username or '--filter' must be specified!" - parser.print_usage() - sys.exit(1) - -if filter is None: - username = args[0] - filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) - -lp = sambaopts.get_loadparm() -creds = credopts.get_credentials(lp) - -if opts.H is not None: - url = opts.H -else: - url = lp.get("sam database") - -samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp) - -samdb.enable_account(filter) -- cgit From 9e5ef916d41ee5f27616d18e431a9943310d3db6 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 20:40:11 +0100 Subject: net: Move 'newuser' to 'net newuser' Signed-off-by: Andrew Tridgell --- source4/script/installmisc.sh | 2 +- source4/scripting/python/samba/netcmd/__init__.py | 15 +++-- source4/scripting/python/samba/netcmd/newuser.py | 70 +++++++++++++++++++++++ source4/setup/newuser | 69 ---------------------- source4/setup/tests/blackbox_newuser.sh | 11 ++-- source4/setup/tests/blackbox_setpassword.sh | 10 ++-- 6 files changed, 93 insertions(+), 84 deletions(-) create mode 100755 source4/scripting/python/samba/netcmd/newuser.py delete mode 100755 source4/setup/newuser (limited to 'source4') diff --git a/source4/script/installmisc.sh b/source4/script/installmisc.sh index b0e575448b..15fc64544c 100755 --- a/source4/script/installmisc.sh +++ b/source4/script/installmisc.sh @@ -49,7 +49,7 @@ cp setup/ad-schema/*.txt $SETUPDIR/ad-schema || exit 1 cp setup/display-specifiers/*.txt $SETUPDIR/display-specifiers || exit 1 echo "Installing sbin scripts from setup/*" -for p in enableaccount newuser provision +for p in provision do cp setup/$p $SBINDIR || exit 1 chmod a+x $SBINDIR/$p diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index 3213dd71b3..9798f3529b 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -81,12 +81,15 @@ class Command(object): for option in option_group.option_list: del kwargs[option.dest] kwargs.update(optiongroups) + min_args = 0 + max_args = 0 for i, arg in enumerate(self.takes_args): - if arg[-1] != "?": - if len(args) < i: - self.usage(args) - return -1 - if len(args) > len(self.takes_args): + if arg[-1] not in ("?", "*"): + min_args += 1 + max_args += 1 + if arg[-1] == "*": + max_args = -1 + if len(args) < min_args or (max_args != -1 and len(args) > max_args): self.usage(args) return -1 try: @@ -137,3 +140,5 @@ from samba.netcmd.setexpiry import cmd_setexpiry commands["setexpiry"] = cmd_setexpiry() from samba.netcmd.enableaccount import cmd_enableaccount commands["enableaccount"] = cmd_enableaccount() +from samba.netcmd.newuser import cmd_newuser +commands["newuser"] = cmd_newuser() diff --git a/source4/scripting/python/samba/netcmd/newuser.py b/source4/scripting/python/samba/netcmd/newuser.py new file mode 100755 index 0000000000..651313a345 --- /dev/null +++ b/source4/scripting/python/samba/netcmd/newuser.py @@ -0,0 +1,70 @@ +#!/usr/bin/python +# +# Adds a new user to a Samba4 server +# Copyright Jelmer Vernooij 2008 +# +# Based on the original in EJS: +# Copyright Andrew Tridgell 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 3 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, see . + +import samba.getopt as options +from samba.netcmd import Command, CommandError, Option + +from getpass import getpass +from samba.auth import system_session +from samba.samdb import SamDB + +class cmd_newuser(Command): + """Create a new user.""" + + synopsis = "newuser [options] []" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptions, + } + + takes_options = [ + Option("-H", help="LDB URL for database or target server", type=str), + Option("--unixname", help="Unix Username", type=str), + Option("--must-change-at-next-login", + help="Force password to be changed on next login", + action="store_true"), + ] + + takes_args = ["username", "password?"] + + def run(self, username, password=None, credopts=None, sambaopts=None, + versionopts=None, H=None, unixname=None, + must_change_at_next_login=None): + if password is None: + password = getpass("New Password: ") + + if unixname is None: + unixname = username + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + if H is not None: + url = H + else: + url = lp.get("sam database") + + samdb = SamDB(url=url, session_info=system_session(), credentials=creds, + lp=lp) + samdb.newuser(username, unixname, password, + force_password_change_at_next_login_req=must_change_at_next_login) diff --git a/source4/setup/newuser b/source4/setup/newuser deleted file mode 100755 index ef65d36dfb..0000000000 --- a/source4/setup/newuser +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/python -# -# Adds a new user to a Samba4 server -# Copyright Jelmer Vernooij 2008 -# -# Based on the original in EJS: -# Copyright Andrew Tridgell 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 3 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, see . - -import sys - -# Find right directory when running from source tree -sys.path.insert(0, "bin/python") - -import samba.getopt as options -import optparse - -from getpass import getpass -from samba.auth import system_session -from samba.samdb import SamDB - -parser = optparse.OptionParser("newuser [options] []") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) -parser.add_option_group(options.VersionOptions(parser)) -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) -parser.add_option("-H", help="LDB URL for database or target server", type=str) -parser.add_option("--unixname", help="Unix Username", type=str) -parser.add_option("--must-change-at-next-login", help="Force password to be changed on next login", action="store_true") - -opts, args = parser.parse_args() - -if len(args) == 0: - parser.print_usage() - sys.exit(1) - -username = args[0] -if len(args) > 1: - password = args[1] -else: - password = getpass("New Password: ") - -if opts.unixname is None: - opts.unixname = username - -lp = sambaopts.get_loadparm() -creds = credopts.get_credentials(lp) - -if opts.H is not None: - url = opts.H -else: - url = lp.get("sam database") - -samdb = SamDB(url=url, session_info=system_session(), credentials=creds, lp=lp) - -samdb.newuser(username, opts.unixname, password, force_password_change_at_next_login_req=opts.must_change_at_next_login) diff --git a/source4/setup/tests/blackbox_newuser.sh b/source4/setup/tests/blackbox_newuser.sh index d25c70669b..30e6830be5 100755 --- a/source4/setup/tests/blackbox_newuser.sh +++ b/source4/setup/tests/blackbox_newuser.sh @@ -14,19 +14,20 @@ shift 1 testit "simple-dc" $PYTHON ./setup/provision --server-role="dc" --domain=FOO --realm=foo.example.com --domain-sid=S-1-5-21-4177067393-1453636373-93818738 --targetdir=$PREFIX/simple-dc +net="./bin/net" CONFIG="--configfile=$PREFIX/simple-dc/etc/smb.conf" -testit "newuser" $PYTHON ./setup/newuser $CONFIG testuser testpass +testit "newuser" $net newuser $CONFIG testuser testpass # check the enable account script -testit "enableaccount" $PYTHON ./setup/enableaccount $CONFIG testuser +testit "enableaccount" $net enableaccount $CONFIG testuser # check the enable account script -testit "setpassword" $PYTHON ./setup/setpassword $CONFIG testuser --newpassword=testpass2 +testit "setpassword" $net setpassword $CONFIG testuser --newpassword=testpass2 # check the setexpiry script -testit "noexpiry" $PYTHON ./setup/setexpiry $CONFIG testuser --noexpiry -testit "expiry" $PYTHON ./setup/setexpiry $CONFIG testuser --days=7 +testit "noexpiry" $net setexpiry $CONFIG testuser --noexpiry +testit "expiry" $net setexpiry $CONFIG testuser --days=7 exit $failed diff --git a/source4/setup/tests/blackbox_setpassword.sh b/source4/setup/tests/blackbox_setpassword.sh index 77b41a2424..9f8fa6d2c1 100755 --- a/source4/setup/tests/blackbox_setpassword.sh +++ b/source4/setup/tests/blackbox_setpassword.sh @@ -12,14 +12,16 @@ shift 1 . `dirname $0`/../../../testprogs/blackbox/subunit.sh +net="./bin/net" + testit "simple-dc" $PYTHON ./setup/provision --server-role="dc" --domain=FOO --realm=foo.example.com --domain-sid=S-1-5-21-4177067393-1453636373-93818738 --targetdir=$PREFIX/simple-dc -testit "newuser" $PYTHON ./setup/newuser --configfile=$PREFIX/simple-dc/etc/smb.conf testuser testpass +testit "newuser" $net newuser --configfile=$PREFIX/simple-dc/etc/smb.conf testuser testpass -testit "setpassword" $PYTHON ./setup/setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass +testit "setpassword" $net setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass -testit "setpassword" $PYTHON ./setup/setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass --must-change-at-next-login +testit "setpassword" $net setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass --must-change-at-next-login -testit "pwsettings" $PYTHON ./setup/pwsettings --quiet set --configfile=$PREFIX/simple-dc/etc/smb.conf --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default +testit "pwsettings" $net pwsettings --quiet set --configfile=$PREFIX/simple-dc/etc/smb.conf --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default exit $failed -- cgit From 7effe2d2e30191c067ae1290224d388d96701b53 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 21:06:21 +0100 Subject: net: Support 'super' commands implemented in Python. Signed-off-by: Andrew Tridgell --- source4/scripting/python/samba/netcmd/__init__.py | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index 9798f3529b..a204ab897b 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -40,7 +40,7 @@ class Command(object): name = property(_get_name) - def usage(self, args): + def usage(self, *args): parser, _ = self._create_parser() parser.print_usage() @@ -49,7 +49,7 @@ class Command(object): def _get_synopsis(self): ret = self.name if self.takes_args: - ret += " " + " ".join(self.takes_args) + ret += " " + " ".join([x.upper() for x in self.takes_args]) return ret synopsis = property(_get_synopsis) @@ -90,7 +90,7 @@ class Command(object): if arg[-1] == "*": max_args = -1 if len(args) < min_args or (max_args != -1 and len(args) > max_args): - self.usage(args) + self.usage(*args) return -1 try: return self.run(*args, **kwargs) @@ -108,21 +108,22 @@ class SuperCommand(Command): subcommands = {} - def run(self, subcommand, *args, **kwargs): - if not subcommand in subcommands: - print >>sys.stderr, "ERROR: No such subcommand '%s'" % subcommand - return subcommands[subcommand].run(*args, **kwargs) - - def usage(self, subcommand=None, *args, **kwargs): + def _run(self, myname, subcommand=None, *args): if subcommand is None: - print "Available subcommands" - for subcommand in subcommands: + print "Available subcommands:" + for subcommand in self.subcommands: print "\t%s" % subcommand return 0 + if not subcommand in self.subcommands: + raise CommandError("No such subcommand '%s'" % subcommand) + return self.subcommands[subcommand]._run(subcommand, *args) + + def usage(self, myname, subcommand=None, *args): + if subcommand is None or not subcommand in self.subcommands: + print "Usage: %s (%s) [options]" % (myname, + " | ".join(self.subcommands.keys())) else: - if not subcommand in subcommands: - print >>sys.stderr, "ERROR: No such subcommand '%s'" % subcommand - return subcommands[subcommand].usage(*args, **kwargs) + return self.subcommands[subcommand].usage(*args) class CommandError(Exception): -- cgit From ea5af6e30ca91df3325581f67daab96d688d58fc Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 21:46:32 +0100 Subject: pyldb: Add dom_sid.split in favor of less powerful dom_sid_to_rid(). Signed-off-by: Andrew Tridgell --- source4/lib/ldb/tests/python/ldap.py | 18 +++++++-------- source4/lib/ldb/tests/python/ldap_schema.py | 2 +- source4/librpc/ndr/py_security.c | 36 +++++++++++++++++++++++++++++ source4/scripting/python/pyglue.c | 23 ------------------ source4/scripting/python/samba/__init__.py | 9 -------- 5 files changed, 46 insertions(+), 42 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py index 426d7b38a0..c2920c009e 100755 --- a/source4/lib/ldb/tests/python/ldap.py +++ b/source4/lib/ldb/tests/python/ldap.py @@ -26,7 +26,7 @@ from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE from ldb import Message, MessageElement, Dn from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE -from samba import Ldb, param, dom_sid_to_rid +from samba import Ldb, param from samba import UF_NORMAL_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT from samba import UF_SERVER_TRUST_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT from samba import UF_INTERDOMAIN_TRUST_ACCOUNT @@ -456,7 +456,7 @@ class BasicTests(unittest.TestCase): self.fail() except LdbError, (num, _): self.assertEquals(num, ERR_NAMING_VIOLATION) - + self.delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn) self.ldb.add({ @@ -642,17 +642,17 @@ objectClass: container res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["objectSID"]) self.assertTrue(len(res1) == 1) - group_rid_1 = dom_sid_to_rid(ldb.schema_format_value("objectSID", - res1[0]["objectSID"][0])) + group_rid_1 = security.dom_sid(ldb.schema_format_value("objectSID", + res1[0]["objectSID"][0])).split()[1] res1 = ldb.search("cn=ldaptestgroup2,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["objectSID"]) self.assertTrue(len(res1) == 1) - group_rid_2 = dom_sid_to_rid(ldb.schema_format_value("objectSID", - res1[0]["objectSID"][0])) + group_rid_2 = security.dom_sid(ldb.schema_format_value("objectSID", + res1[0]["objectSID"][0])).split()[1] # Try to create a user with an invalid primary group - try: + try: ldb.add({ "dn": "cn=ldaptestuser,cn=users," + self.base_dn, "objectclass": ["user", "person"], @@ -833,7 +833,7 @@ objectClass: container self.assertTrue(len(res1) == 1) self.assertFalse("primaryGroupToken" in res1[0]) - res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn, + res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn, scope=SCOPE_BASE) self.assertTrue(len(res1) == 1) self.assertFalse("primaryGroupToken" in res1[0]) @@ -843,7 +843,7 @@ objectClass: container self.assertTrue(len(res1) == 1) primary_group_token = int(res1[0]["primaryGroupToken"][0]) - rid = dom_sid_to_rid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0])) + rid = security.dom_sid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0])).split()[1] self.assertEquals(primary_group_token, rid) m = Message() diff --git a/source4/lib/ldb/tests/python/ldap_schema.py b/source4/lib/ldb/tests/python/ldap_schema.py index f13a4fbc52..0a31db82f7 100755 --- a/source4/lib/ldb/tests/python/ldap_schema.py +++ b/source4/lib/ldb/tests/python/ldap_schema.py @@ -26,7 +26,7 @@ from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE from ldb import Message, MessageElement, Dn from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE -from samba import Ldb, param, dom_sid_to_rid +from samba import Ldb from samba import UF_NORMAL_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT from samba import UF_SERVER_TRUST_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT from samba import UF_INTERDOMAIN_TRUST_ACCOUNT diff --git a/source4/librpc/ndr/py_security.c b/source4/librpc/ndr/py_security.c index 02dc059f05..d04e2579f5 100644 --- a/source4/librpc/ndr/py_security.c +++ b/source4/librpc/ndr/py_security.c @@ -41,6 +41,33 @@ static void PyType_AddMethods(PyTypeObject *type, PyMethodDef *methods) } } +static PyObject *py_dom_sid_split(PyObject *py_self, PyObject *args) +{ + struct dom_sid *self = py_talloc_get_ptr(py_self); + struct dom_sid *domain_sid; + TALLOC_CTX *mem_ctx; + uint32_t rid; + NTSTATUS status; + PyObject *py_domain_sid; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + status = dom_sid_split_rid(mem_ctx, self, &domain_sid, &rid); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetString(PyExc_RuntimeError, "dom_sid_split_rid failed"); + talloc_free(mem_ctx); + return NULL; + } + + py_domain_sid = py_talloc_steal(&dom_sid_Type, domain_sid); + talloc_free(mem_ctx); + return Py_BuildValue("(OI)", py_domain_sid, rid); +} + static int py_dom_sid_cmp(PyObject *py_self, PyObject *py_other) { struct dom_sid *self = py_talloc_get_ptr(py_self), *other; @@ -86,12 +113,21 @@ static int py_dom_sid_init(PyObject *self, PyObject *args, PyObject *kwargs) return 0; } +static PyMethodDef py_dom_sid_extra_methods[] = { + { "split", (PyCFunction)py_dom_sid_split, METH_NOARGS, + "S.split() -> (domain_sid, rid)\n" + "Split a domain sid" }, + { NULL } +}; + + static void py_dom_sid_patch(PyTypeObject *type) { type->tp_init = py_dom_sid_init; type->tp_str = py_dom_sid_str; type->tp_repr = py_dom_sid_repr; type->tp_compare = py_dom_sid_cmp; + PyType_AddMethods(type, py_dom_sid_extra_methods); } #define PY_DOM_SID_PATCH py_dom_sid_patch diff --git a/source4/scripting/python/pyglue.c b/source4/scripting/python/pyglue.c index 9f01102316..3d33e605db 100644 --- a/source4/scripting/python/pyglue.c +++ b/source4/scripting/python/pyglue.c @@ -442,27 +442,6 @@ static PyObject *py_dsdb_make_schema_global(PyObject *self, PyObject *args) Py_RETURN_NONE; } -static PyObject *py_dom_sid_to_rid(PyLdbObject *self, PyObject *args) -{ - PyObject *py_sid; - struct dom_sid *sid; - uint32_t rid; - NTSTATUS status; - - if(!PyArg_ParseTuple(args, "O", &py_sid)) - return NULL; - - sid = dom_sid_parse_talloc(NULL, PyString_AsString(py_sid)); - - status = dom_sid_split_rid(NULL, sid, NULL, &rid); - if (!NT_STATUS_IS_OK(status)) { - PyErr_SetString(PyExc_RuntimeError, "dom_sid_split_rid failed"); - return NULL; - } - - return PyInt_FromLong(rid); -} - static PyMethodDef py_misc_methods[] = { { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS, "random_password(len) -> string\n" @@ -506,8 +485,6 @@ static PyMethodDef py_misc_methods[] = { NULL }, { "dsdb_make_schema_global", (PyCFunction)py_dsdb_make_schema_global, METH_VARARGS, NULL }, - { "dom_sid_to_rid", (PyCFunction)py_dom_sid_to_rid, METH_VARARGS, - NULL }, { "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS, "set debug level" }, { NULL } diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index f74304c01c..d501fd7b88 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -370,15 +370,6 @@ def valid_netbios_name(name): return True -def dom_sid_to_rid(sid_str): - """Converts a domain SID to the relative RID. - - :param sid_str: The domain SID formatted as string - """ - - return glue.dom_sid_to_rid(sid_str) - - version = glue.version # "userAccountControl" flags -- cgit From 66f81d18ce08cfb1ed6c347a753b436d3de8ced7 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 21:48:42 +0100 Subject: samba: Fix whitespace, remove pointless 'pass' statement. Signed-off-by: Andrew Tridgell --- source4/scripting/python/samba/__init__.py | 53 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 27 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index d501fd7b88..5d61c1bd8c 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -2,20 +2,20 @@ # Unix SMB/CIFS implementation. # Copyright (C) Jelmer Vernooij 2007-2008 -# +# # Based on the original in EJS: # Copyright (C) Andrew Tridgell 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 3 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, see . # @@ -45,11 +45,11 @@ import ldb import glue class Ldb(ldb.Ldb): - """Simple Samba-specific LDB subclass that takes care + """Simple Samba-specific LDB subclass that takes care of setting up the modules dir, credentials pointers, etc. - - Please note that this is intended to be for all Samba LDB files, - not necessarily the Sam database. For Sam-specific helper + + Please note that this is intended to be for all Samba LDB files, + not necessarily the Sam database. For Sam-specific helper functions see samdb.py. """ def __init__(self, url=None, lp=None, modules_dir=None, session_info=None, @@ -65,7 +65,7 @@ class Ldb(ldb.Ldb): :param options: Additional options (optional) This is different from a regular Ldb file in that the Samba-specific - modules-dir is used by default and that credentials and session_info + modules-dir is used by default and that credentials and session_info can be passed through (required by some modules). """ @@ -122,10 +122,10 @@ class Ldb(ldb.Ldb): # need one public, we will have to change this here super(Ldb, self).set_create_perms(perms) - def searchone(self, attribute, basedn=None, expression=None, + def searchone(self, attribute, basedn=None, expression=None, scope=ldb.SCOPE_BASE): """Search for one attribute as a string. - + :param basedn: BaseDN for the search. :param attribute: Name of the attribute :param expression: Optional search expression. @@ -166,7 +166,7 @@ class Ldb(ldb.Ldb): self.erase_users_computers(basedn) # Delete the 'visible' records, and the invisble 'deleted' records (if this DB supports it) - for msg in self.search(basedn, ldb.SCOPE_SUBTREE, + for msg in self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", [], controls=["show_deleted:0"]): try: @@ -174,14 +174,14 @@ class Ldb(ldb.Ldb): except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _): # Ignore no such object errors pass - - res = self.search(basedn, ldb.SCOPE_SUBTREE, + + res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", [], controls=["show_deleted:0"]) assert len(res) == 0 # delete the specials - for attr in ["@SUBCLASSES", "@MODULES", + for attr in ["@SUBCLASSES", "@MODULES", "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: try: self.delete(attr) @@ -191,7 +191,7 @@ class Ldb(ldb.Ldb): def erase(self): """Erase this ldb, removing all records.""" - + self.erase_except_schema_controlled() # delete the specials @@ -207,13 +207,12 @@ class Ldb(ldb.Ldb): def erase_recursive(self, dn): try: - res = self.search(base=dn, scope=ldb.SCOPE_ONELEVEL, attrs=[], + res = self.search(base=dn, scope=ldb.SCOPE_ONELEVEL, attrs=[], controls=["show_deleted:0"]) except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _): # Ignore no such object errors return - pass - + for msg in res: erase_recursive(self, msg.dn) @@ -223,7 +222,7 @@ class Ldb(ldb.Ldb): # Ignore no such object errors pass - res = self.search("", ldb.SCOPE_BASE, "(objectClass=*)", + res = self.search("", ldb.SCOPE_BASE, "(objectClass=*)", ["namingContexts"]) assert len(res) == 1 if not "namingContexts" in res[0]: @@ -285,14 +284,14 @@ class Ldb(ldb.Ldb): def set_invocation_id(self, invocation_id): """Set the invocation id for this SamDB handle. - + :param invocation_id: GUID of the invocation id. """ glue.dsdb_set_ntds_invocation_id(self, invocation_id) def set_opaque_integer(self, name, value): """Set an integer as an opaque (a flag or other value) value on the database - + :param name: The name for the opaque value :param value: The integer value """ @@ -302,7 +301,7 @@ class Ldb(ldb.Ldb): def substitute_var(text, values): """substitute strings of the form ${NAME} in str, replacing with substitutions from subobj. - + :param text: Text in which to subsitute. :param values: Dictionary with keys and values. """ @@ -318,21 +317,21 @@ def substitute_var(text, values): def check_all_substituted(text): """Make sure that all substitution variables in a string have been replaced. If not, raise an exception. - + :param text: The text to search for substitution variables """ if not "${" in text: return - + var_start = text.find("${") var_end = text.find("}", var_start) - + raise Exception("Not all variables substituted: %s" % text[var_start:var_end+1]) def read_and_sub_file(file, subst_vars): """Read a file and sub in variables found in it - + :param file: File to be read (typically from setup directory) param subst_vars: Optional variables to subsitute in the file. """ -- cgit From dbd7a62baa56eb2ce082fdcf24e2d8621a4f54ea Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Dec 2009 21:59:50 +0100 Subject: py/security: Add test for dom_sid.split. Signed-off-by: Andrew Tridgell --- source4/libcli/security/tests/bindings.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/libcli/security/tests/bindings.py b/source4/libcli/security/tests/bindings.py index 00fa05d070..6fe3d5471d 100644 --- a/source4/libcli/security/tests/bindings.py +++ b/source4/libcli/security/tests/bindings.py @@ -2,17 +2,17 @@ # Unix SMB/CIFS implementation. # Copyright (C) Jelmer Vernooij 2007 -# +# # 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 3 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, see . # @@ -46,6 +46,7 @@ class SecurityTokenTests(unittest.TestCase): class SecurityDescriptorTests(unittest.TestCase): + def setUp(self): self.descriptor = security.descriptor() @@ -100,6 +101,10 @@ class SecurityDescriptorTests(unittest.TestCase): desc1 = security.descriptor.from_sddl(text, dom) self.assertNotEqual(desc1.as_sddl(), desc1.as_sddl(dom)) + def test_split(self): + dom = security.dom_sid("S-2-0-7") + self.assertEquals((security.dom_sid("S-2-0"), 7), dom.split()) + class DomSidTests(unittest.TestCase): def test_parse_sid(self): -- cgit From 3239872bbcd81a690663f29c8fa20811d66f9dea Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 31 Dec 2009 16:52:15 +1100 Subject: s4-net: fixed pwsettings command Don't override user settings with current settings --- source4/scripting/python/samba/netcmd/pwsettings.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/netcmd/pwsettings.py b/source4/scripting/python/samba/netcmd/pwsettings.py index eb3bb65790..30f6f20d68 100644 --- a/source4/scripting/python/samba/netcmd/pwsettings.py +++ b/source4/scripting/python/samba/netcmd/pwsettings.py @@ -88,10 +88,10 @@ class cmd_pwsettings(Command): try: pwd_props = int(res[0]["pwdProperties"][0]) pwd_hist_len = int(res[0]["pwdHistoryLength"][0]) - min_pwd_len = int(res[0]["minPwdLength"][0]) + cur_min_pwd_len = int(res[0]["minPwdLength"][0]) # ticks -> days - min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24)) - max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24)) + cur_min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24)) + cur_max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24)) except KeyError: raise CommandError("Could not retrieve password properties!") @@ -103,9 +103,9 @@ class cmd_pwsettings(Command): else: self.message("Password complexity: off") self.message("Password history length: %d" % pwd_hist_len) - self.message("Minimum password length: %d" % min_pwd_len) - self.message("Minimum password age (days): %d" % min_pwd_age) - self.message("Maximum password age (days): %d" % max_pwd_age) + self.message("Minimum password length: %d" % cur_min_pwd_len) + self.message("Minimum password age (days): %d" % cur_min_pwd_age) + self.message("Maximum password age (days): %d" % cur_max_pwd_age) elif subcommand == "set": msgs = [] m = ldb.Message() -- cgit From de9485784867a7a68207e42fe2a021de01e54904 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 31 Dec 2009 16:53:14 +1100 Subject: s4-net: fixed finddcs to use empty SID instead of NULL sid (NDR error) --- source4/libcli/finddcs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source4') diff --git a/source4/libcli/finddcs.c b/source4/libcli/finddcs.c index 8330042ea1..04b25d37ef 100644 --- a/source4/libcli/finddcs.c +++ b/source4/libcli/finddcs.c @@ -158,6 +158,9 @@ static void finddcs_name_resolved(struct composite_context *ctx) if (composite_nomem(state->r.in.my_accountname, state->ctx)) return; state->r.in.account_control = ACB_WSTRUST; state->r.in.domain_sid = state->domain_sid; + if (state->r.in.domain_sid == NULL) { + state->r.in.domain_sid = talloc_zero(state, struct dom_sid); + } ireq = irpc_call_send(state->msg_ctx, nbt_servers[0], &ndr_table_irpc, NDR_NBTD_GETDCNAME, -- cgit From 0c2964035888c3af63f274078c75e195153c46be Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 1 Jan 2010 18:31:44 +0100 Subject: s4/build: Indicate whether Samba4 is being built against the system Heimdal. --- source4/build/smb_build/summary.pm | 1 + 1 file changed, 1 insertion(+) (limited to 'source4') diff --git a/source4/build/smb_build/summary.pm b/source4/build/smb_build/summary.pm index 153c3e20e9..09f5ff83ce 100644 --- a/source4/build/smb_build/summary.pm +++ b/source4/build/smb_build/summary.pm @@ -65,6 +65,7 @@ sub show($$) showisexternal($output, "tdb", "LIBTDB"); showisexternal($output, "tevent", "LIBTEVENT"); showisexternal($output, "ldb", "LIBLDB"); + showisexternal($output, "heimdal", "HEIMDAL_KRB5"); print "Developer mode: ".(enabled($config->{developer})?"yes":"no")."\n"; print "Automatic dependencies: ". (enabled($config->{automatic_dependencies}) -- cgit From 9085499bbb518bdfa91f9c02103ad058b0b06192 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 1 Jan 2010 18:32:37 +0100 Subject: heimdal_build: Explicitly specify 'YES' when enabling external libraries. --- source4/heimdal_build/external.m4 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/heimdal_build/external.m4 b/source4/heimdal_build/external.m4 index 3cd8900a12..ad9443f999 100644 --- a/source4/heimdal_build/external.m4 +++ b/source4/heimdal_build/external.m4 @@ -12,7 +12,7 @@ SMB_EXT_LIB(HEIMDAL_KRB5, [${HEIMDAL_KRB5_CFLAGS}], [${HEIMDAL_KRB5_CPPFLAGS}], [${HEIMDAL_KRB5_LDFLAGS}]) -SMB_ENABLE(HEIMDAL_KRB5) +SMB_ENABLE(HEIMDAL_KRB5,YES) AC_DEFINE(HAVE_KRB5,1,[Whether kerberos is available]) HAVE_KRB5=YES AC_DEFINE(HAVE_COM_ERR,1,[Whether com_err is available]) @@ -27,7 +27,7 @@ SMB_EXT_LIB(HEIMDAL_GSSAPI, [${HEIMDAL_GSSAPI_CFLAGS}], [${HEIMDAL_GSSAPI_CPPFLAGS}], [${HEIMDAL_GSSAPI_LDFLAGS}]) -SMB_ENABLE(HEIMDAL_GSSAPI) +SMB_ENABLE(HEIMDAL_GSSAPI,YES) AC_DEFINE(HAVE_GSSAPI,1,[Whether GSSAPI is available]) HAVE_GSSAPI=YES @@ -40,7 +40,7 @@ SMB_EXT_LIB(HEIMDAL_HDB, [${HEIMDAL_HDB_CFLAGS}], [${HEIMDAL_HDB_CPPFLAGS}], [${HEIMDAL_HDB_LDFLAGS}]) -SMB_ENABLE(HEIMDAL_HDB) +SMB_ENABLE(HEIMDAL_HDB,YES) HEIMDAL_KDC_LIBS="-lkdc" HEIMDAL_KDC_CFLAGS="" @@ -51,4 +51,4 @@ SMB_EXT_LIB(HEIMDAL_KDC, [${HEIMDAL_KDC_CFLAGS}], [${HEIMDAL_KDC_CPPFLAGS}], [${HEIMDAL_KDC_LDFLAGS}]) -SMB_ENABLE(HEIMDAL_KDC) +SMB_ENABLE(HEIMDAL_KDC,YES) -- cgit From 41c3c979ffc6b8eee795ec0616115b31f5dfd636 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 10 Dec 2009 23:48:30 +1100 Subject: s4-dsdb: add support for storing linked attribute meta data in extended DNs When in functional levels above w2k, we need to store much richer meta data about linkked attributes. We also need to keep deleted linked attributes around to allow the deletion to be propogated to other DCs. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 585 +++++++++++++++++++++++- 1 file changed, 566 insertions(+), 19 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3d31cc3f49..7e1d7189b1 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -46,6 +46,9 @@ #include "libcli/security/dom_sid.h" #include "lib/util/dlinklist.h" #include "dsdb/samdb/ldb_modules/util.h" +#include "lib/util/binsearch.h" + +#define W2K3_LINKED_ATTRIBUTES 1 struct replmd_private { TALLOC_CTX *la_ctx; @@ -680,6 +683,20 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, for (i=0; ictr.ctr1.count; i++) { if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break; } + +#if W2K3_LINKED_ATTRIBUTES + if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) { + /* linked attributes are not stored in + replPropertyMetaData in FL above w2k, but we do + raise the seqnum for the object */ + if (*seq_num == 0 && + ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + return LDB_SUCCESS; + } +#endif + if (i == omd->ctr.ctr1.count) { /* we need to add a new one */ omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array, @@ -721,13 +738,13 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, */ static int replmd_update_rpmd(struct ldb_module *module, const struct dsdb_schema *schema, - struct ldb_message *msg, uint64_t *seq_num) + struct ldb_message *msg, uint64_t *seq_num, + time_t t) { const struct ldb_val *omd_value; enum ndr_err_code ndr_err; struct replPropertyMetaDataBlob omd; int i; - time_t t = time(NULL); NTTIME now; const struct GUID *our_invocation_id; int ret; @@ -830,13 +847,555 @@ static int replmd_update_rpmd(struct ldb_module *module, } +struct parsed_dn { + struct dsdb_dn *dsdb_dn; + struct GUID *guid; + struct ldb_val *v; +}; + +static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2) +{ + return GUID_compare(pdn1->guid, pdn2->guid); +} + +static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid) +{ + struct parsed_dn *ret; + BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret); + return ret; +} + +/* + get a series of message element values as an array of DNs and GUIDs + the result is sorted by GUID + */ +static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, + struct ldb_message_element *el, struct parsed_dn **pdn, + const char *ldap_oid) +{ + int i; + struct ldb_context *ldb = ldb_module_get_ctx(module); + + if (el == NULL) { + *pdn = NULL; + return LDB_SUCCESS; + } + + (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values); + if (!*pdn) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i=0; inum_values; i++) { + struct ldb_val *v = &el->values[i]; + NTSTATUS status; + struct ldb_dn *dn; + struct parsed_dn *p; + + p = &(*pdn)[i]; + + p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid); + if (p->dsdb_dn == NULL) { + return LDB_ERR_INVALID_DN_SYNTAX; + } + + dn = p->dsdb_dn->dn; + + p->guid = talloc(*pdn, struct GUID); + if (p->guid == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + status = dsdb_get_extended_dn_guid(dn, p->guid); + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + /* we got a DN without a GUID - go find the GUID */ + int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n", + ldb_dn_get_linearized(dn)); + return ret; + } + } else if (!NT_STATUS_IS_OK(status)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* keep a pointer to the original ldb_val */ + p->v = v; + } + + qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare); + + return LDB_SUCCESS; +} + +/* + build a new extended DN, including all meta data fields + + DELETED = 1 or missing + RMD_ADDTIME = originating_add_time + RMD_INVOCID = originating_invocation_id + RMD_CHANGETIME = originating_change_time + RMD_USN = originating_usn + RMD_VERSION = version + */ +static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p, + const struct GUID *invocation_id, uint64_t seq_num, time_t t) +{ + struct ldb_dn *dn = p->dsdb_dn->dn; + NTTIME now; + const char *tstring, *usn_string; + struct ldb_val tval; + struct ldb_val iid; + struct ldb_val usnv; + struct ldb_val vers; + NTSTATUS status; + int ret; + const char *dnstring; + + unix_to_nt_time(&now, t); + tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now); + if (!tstring) { + return LDB_ERR_OPERATIONS_ERROR; + } + tval = data_blob_string_const(tstring); + + usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num); + if (!usn_string) { + return LDB_ERR_OPERATIONS_ERROR; + } + usnv = data_blob_string_const(usn_string); + + vers = data_blob_string_const("0"); + + status = GUID_to_ndr_blob(invocation_id, dn, &iid); + if (!NT_STATUS_IS_OK(status)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); + if (ret != LDB_SUCCESS) return ret; + + dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1); + if (dnstring == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + *v = data_blob_string_const(dnstring); + + return LDB_SUCCESS; +} + + +/* + update an extended DN, including all meta data fields + + see replmd_build_la_val for value names + */ +static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p, + struct parsed_dn *old_p, const struct GUID *invocation_id, + uint64_t seq_num, time_t t, bool deleted) +{ + struct ldb_dn *dn = p->dsdb_dn->dn; + NTTIME now; + const char *tstring, *usn_string; + struct ldb_val tval; + struct ldb_val iid; + struct ldb_val usnv; + struct ldb_val vers; + const struct ldb_val *old_addtime, *old_version; + NTSTATUS status; + int ret; + const char *dnstring; + + unix_to_nt_time(&now, t); + tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now); + if (!tstring) { + return LDB_ERR_OPERATIONS_ERROR; + } + tval = data_blob_string_const(tstring); + + usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num); + if (!usn_string) { + return LDB_ERR_OPERATIONS_ERROR; + } + usnv = data_blob_string_const(usn_string); + + status = GUID_to_ndr_blob(invocation_id, dn, &iid); + if (!NT_STATUS_IS_OK(status)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (deleted) { + struct ldb_val dv; + dv = data_blob_string_const("1"); + ret = ldb_dn_set_extended_component(dn, "DELETED", &dv); + } else { + ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + } + if (ret != LDB_SUCCESS) return ret; + + /* get the ADDTIME from the original */ + old_addtime = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_ADDTIME"); + if (old_addtime == NULL) { + old_addtime = &tval; + } + if (p != old_p) { + ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime); + if (ret != LDB_SUCCESS) return ret; + } + + /* use our invocation id */ + ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid); + if (ret != LDB_SUCCESS) return ret; + + /* changetime is the current time */ + ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval); + if (ret != LDB_SUCCESS) return ret; + + /* update the USN */ + ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv); + if (ret != LDB_SUCCESS) return ret; + + /* increase the version by 1 */ + old_version = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_VERSION"); + if (old_version == NULL) { + vers = data_blob_string_const("0"); + } else { + char *vstring; + vstring = talloc_strndup(dn, (const char *)old_version->data, old_version->length); + if (!vstring) { + return LDB_ERR_OPERATIONS_ERROR; + } + vstring = talloc_asprintf(dn, "%lu", + (unsigned long)strtoul(vstring, NULL, 0)+1); + vers = data_blob_string_const(vstring); + } + ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); + if (ret != LDB_SUCCESS) return ret; + + dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1); + if (dnstring == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + *v = data_blob_string_const(dnstring); + + return LDB_SUCCESS; +} + +/* + handle adding a linked attribute + */ +static int replmd_modify_la_add(struct ldb_module *module, + struct ldb_message *msg, + struct ldb_message_element *el, + struct ldb_message_element *old_el, + const struct dsdb_attribute *schema_attr, + uint64_t seq_num, + time_t t) +{ + int i; + struct parsed_dn *dns, *old_dns; + TALLOC_CTX *tmp_ctx = talloc_new(msg); + int ret; + struct ldb_val *new_values = NULL; + unsigned int num_new_values = 0; + unsigned old_num_values = old_el?old_el->num_values:0; + const struct GUID *invocation_id; + struct ldb_context *ldb = ldb_module_get_ctx(module); + + ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + invocation_id = samdb_ntds_invocation_id(ldb); + if (!invocation_id) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* for each new value, see if it exists already with the same GUID */ + for (i=0; inum_values; i++) { + struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid); + if (p == NULL) { + /* this is a new linked attribute value */ + new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1); + if (new_values == NULL) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i], + invocation_id, seq_num, t); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + num_new_values++; + } else { + /* this is only allowed if the GUID was + previously deleted. */ + const struct ldb_val *v; + v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); + if (v == NULL) { + ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s", + el->name, GUID_string(tmp_ctx, p->guid)); + talloc_free(tmp_ctx); + return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; + } + ret = replmd_update_la_val(old_el->values, p->v, &dns[i], p, invocation_id, seq_num, t, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + } + + /* add the new ones on to the end of the old values, constructing a new el->values */ + el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL, + struct ldb_val, old_num_values+num_new_values); + if (el->values == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val)); + el->num_values = old_num_values + num_new_values; + + talloc_steal(msg->elements, el->values); + talloc_steal(el->values, new_values); + + talloc_free(tmp_ctx); + + /* we now tell the backend to replace all existing values + with the one we have constructed */ + el->flags = LDB_FLAG_MOD_REPLACE; + + return LDB_SUCCESS; +} + + +/* + handle replacing a linked attribute + */ +static int replmd_modify_la_replace(struct ldb_module *module, + struct ldb_message *msg, + struct ldb_message_element *el, + struct ldb_message_element *old_el, + const struct dsdb_attribute *schema_attr, + uint64_t seq_num, + time_t t) +{ + return LDB_SUCCESS; +} + +/* + handle deleting all active linked attributes + */ +static int replmd_modify_la_delete(struct ldb_module *module, + struct ldb_message *msg, + struct ldb_message_element *el, + struct ldb_message_element *old_el, + const struct dsdb_attribute *schema_attr, + uint64_t seq_num, + time_t t) +{ + int i; + struct parsed_dn *dns, *old_dns; + TALLOC_CTX *tmp_ctx = talloc_new(msg); + int ret; + const struct GUID *invocation_id; + struct ldb_context *ldb = ldb_module_get_ctx(module); + + /* check if there is nothing to delete */ + if ((!old_el || old_el->num_values == 0) && + el->num_values == 0) { + return LDB_SUCCESS; + } + + if (!old_el || old_el->num_values == 0) { + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + + ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + invocation_id = samdb_ntds_invocation_id(ldb); + if (!invocation_id) { + return LDB_ERR_OPERATIONS_ERROR; + } + + el->values = NULL; + + /* see if we are being asked to delete any links that + don't exist or are already deleted */ + for (i=0; inum_values; i++) { + struct parsed_dn *p = &dns[i]; + struct parsed_dn *p2; + const struct ldb_val *v; + + p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid); + if (!p2) { + ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s", + el->name, GUID_string(tmp_ctx, p->guid)); + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); + if (v) { + ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s", + el->name, GUID_string(tmp_ctx, p->guid)); + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + } + + /* for each new value, see if it exists already with the same GUID + if it is not already deleted and matches the delete list then delete it + */ + for (i=0; inum_values; i++) { + struct parsed_dn *p = &old_dns[i]; + const struct ldb_val *v; + + if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) { + continue; + } + + v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); + if (v != NULL) continue; + + ret = replmd_update_la_val(old_el->values, p->v, p, p, invocation_id, seq_num, t, true); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + el->values = talloc_steal(msg->elements, old_el->values); + el->num_values = old_el->num_values; + + talloc_free(tmp_ctx); + + /* we now tell the backend to replace all existing values + with the one we have constructed */ + el->flags = LDB_FLAG_MOD_REPLACE; + + return LDB_SUCCESS; +} + + + +/* + handle linked attributes in modify requests + */ +static int replmd_modify_handle_linked_attribs(struct ldb_module *module, + struct ldb_message *msg, + uint64_t seq_num, time_t t) +{ + struct ldb_result *res; + int ret, i; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_message *old_msg; + struct dsdb_schema *schema = dsdb_get_schema(ldb); + + if (seq_num == 0) { + /* there the replmd_update_rpmd code has already + * checked and saw that there are no linked + * attributes */ + return LDB_SUCCESS; + } + +#if !W2K3_LINKED_ATTRIBUTES + return LDB_SUCCESS; +#endif + + if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) { + /* don't do anything special for linked attributes */ + return LDB_SUCCESS; + } + + ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL, + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + if (ret != LDB_SUCCESS) { + return ret; + } + old_msg = res->msgs[0]; + + for (i=0; inum_elements; i++) { + struct ldb_message_element *el = &msg->elements[i]; + struct ldb_message_element *old_el; + const struct dsdb_attribute *schema_attr + = dsdb_attribute_by_lDAPDisplayName(schema, el->name); + if (!schema_attr) { + ldb_asprintf_errstring(ldb, + "attribute %s is not a valid attribute in schema", el->name); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + if (schema_attr->linkID == 0) { + continue; + } + if ((schema_attr->linkID & 1) == 1) { + /* Odd is for the target. Illegal to modify */ + ldb_asprintf_errstring(ldb, + "attribute %s must not be modified directly, it is a linked attribute", el->name); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + old_el = ldb_msg_find_element(old_msg, el->name); + switch (el->flags) { + case LDB_FLAG_MOD_REPLACE: + ret = replmd_modify_la_replace(module, msg, el, old_el, schema_attr, seq_num, t); + break; + case LDB_FLAG_MOD_DELETE: + ret = replmd_modify_la_delete(module, msg, el, old_el, schema_attr, seq_num, t); + break; + case LDB_FLAG_MOD_ADD: + ret = replmd_modify_la_add(module, msg, el, old_el, schema_attr, seq_num, t); + break; + default: + ldb_asprintf_errstring(ldb, + "invalid flags 0x%x for %s linked attribute", + el->flags, el->name); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + } + + talloc_free(res); + return ret; +} + + + static int replmd_modify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; struct replmd_replicated_request *ac; struct ldb_request *down_req; struct ldb_message *msg; - struct ldb_result *res; time_t t = time(NULL); int ret; @@ -862,24 +1421,13 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - /* TODO: - * - give an error when a readonly attribute should - * be modified - * - merge the changed into the old object - * if the caller set values to the same value - * ignore the attribute, return success when no - * attribute was changed - */ - - ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL, - DSDB_SEARCH_SHOW_DELETED | - DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(ac); return ret; } - ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num); + ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(ac); return ret; @@ -1970,6 +2518,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module, struct ldb_message_element el; const struct ldb_val *guid; WERROR status; + time_t t = time(NULL); drs.value_ctr.num_values = 1; drs.value_ctr.values = &val; @@ -2077,7 +2626,7 @@ linked_attributes[0]: el.values[0] = data_blob_string_const(dsdb_dn_get_extended_linearized(tmp_ctx, dsdb_dn, 1)); } - ret = replmd_update_rpmd(module, schema, msg, &seq_num); + ret = replmd_update_rpmd(module, schema, msg, &seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2086,8 +2635,6 @@ linked_attributes[0]: /* we only change whenChanged and uSNChanged if the seq_num has changed */ if (seq_num != 0) { - time_t t = time(NULL); - if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; -- cgit From d5020e3d917713549cee82d66fbcc78b88cebd6a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 10 Dec 2009 23:49:02 +1100 Subject: s4-dsdb: add a TODO item for linked attributes in extended_dn_out Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/extended_dn_in.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c index 89ba7bb04b..33931167c5 100644 --- a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c @@ -34,6 +34,11 @@ #include "ldb/include/ldb_errors.h" #include "ldb/include/ldb_module.h" +/* + TODO: if relax is not set then we need to reject the fancy RMD_* and + DELETED extended DN codes + */ + /* search */ struct extended_search_context { struct ldb_module *module; -- cgit From dee6b6fb3db03d371356b6d54d63bfde8ef153ae Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 14 Dec 2009 21:54:41 +1100 Subject: s4-dsdb: implemeneted replmd_modify_la_replace() We now have the core code for handling storage of linked attribute meta-data with local modifies Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 170 +++++++++++++++++++++--- 1 file changed, 152 insertions(+), 18 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 7e1d7189b1..249dd61a4a 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1170,7 +1170,8 @@ static int replmd_modify_la_add(struct ldb_module *module, /* add the new ones on to the end of the old values, constructing a new el->values */ el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL, - struct ldb_val, old_num_values+num_new_values); + struct ldb_val, + old_num_values+num_new_values); if (el->values == NULL) { ldb_module_oom(module); return LDB_ERR_OPERATIONS_ERROR; @@ -1192,20 +1193,6 @@ static int replmd_modify_la_add(struct ldb_module *module, } -/* - handle replacing a linked attribute - */ -static int replmd_modify_la_replace(struct ldb_module *module, - struct ldb_message *msg, - struct ldb_message_element *el, - struct ldb_message_element *old_el, - const struct dsdb_attribute *schema_attr, - uint64_t seq_num, - time_t t) -{ - return LDB_SUCCESS; -} - /* handle deleting all active linked attributes */ @@ -1266,7 +1253,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, el->name, GUID_string(tmp_ctx, p->guid)); return LDB_ERR_NO_SUCH_ATTRIBUTE; } - v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); + v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED"); if (v) { ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s", el->name, GUID_string(tmp_ctx, p->guid)); @@ -1307,6 +1294,134 @@ static int replmd_modify_la_delete(struct ldb_module *module, return LDB_SUCCESS; } +/* + handle replacing a linked attribute + */ +static int replmd_modify_la_replace(struct ldb_module *module, + struct ldb_message *msg, + struct ldb_message_element *el, + struct ldb_message_element *old_el, + const struct dsdb_attribute *schema_attr, + uint64_t seq_num, + time_t t) +{ + int i; + struct parsed_dn *dns, *old_dns; + TALLOC_CTX *tmp_ctx = talloc_new(msg); + int ret; + const struct GUID *invocation_id; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_val *new_values = NULL; + uint32_t num_new_values = 0; + unsigned old_num_values = old_el?old_el->num_values:0; + + /* check if there is nothing to replace */ + if ((!old_el || old_el->num_values == 0) && + el->num_values == 0) { + return LDB_SUCCESS; + } + + ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + invocation_id = samdb_ntds_invocation_id(ldb); + if (!invocation_id) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* mark all the old ones as deleted */ + for (i=0; inum_values, old_p->guid); + if (p) { + /* we don't delete it if we are re-adding it */ + continue; + } + v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); + if (v) continue; + + ret = replmd_update_la_val(old_el->values, old_p->v, old_p, old_p, + invocation_id, seq_num, t, true); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + /* for each new value, either update its meta-data, or add it + * to old_el + */ + for (i=0; inum_values; i++) { + struct parsed_dn *p = &dns[i], *old_p; + + if (old_dns && + (old_p = parsed_dn_find(old_dns, + old_num_values, p->guid)) != NULL) { + /* update in place */ + ret = replmd_update_la_val(old_el->values, old_p->v, old_p, + old_p, invocation_id, + seq_num, t, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } else { + /* add a new one */ + new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, + num_new_values+1); + if (new_values == NULL) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i], + invocation_id, seq_num, t); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + num_new_values++; + } + } + + /* add the new values to the end of old_el */ + if (num_new_values != 0) { + el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL, + struct ldb_val, old_num_values+num_new_values); + if (el->values == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + memcpy(&el->values[old_num_values], &new_values[0], + sizeof(struct ldb_val)*num_new_values); + el->num_values = old_num_values + num_new_values; + talloc_steal(msg->elements, new_values); + } else { + el->values = old_el->values; + el->num_values = old_el->num_values; + talloc_steal(msg->elements, el->values); + } + + talloc_free(tmp_ctx); + + /* we now tell the backend to replace all existing values + with the one we have constructed */ + el->flags = LDB_FLAG_MOD_REPLACE; + + return LDB_SUCCESS; +} /* @@ -1340,6 +1455,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL, DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_REVEAL_INTERNALS | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); if (ret != LDB_SUCCESS) { return ret; @@ -1348,7 +1464,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, for (i=0; inum_elements; i++) { struct ldb_message_element *el = &msg->elements[i]; - struct ldb_message_element *old_el; + struct ldb_message_element *old_el, *new_el; const struct dsdb_attribute *schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name); if (!schema_attr) { @@ -1366,7 +1482,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, return LDB_ERR_UNWILLING_TO_PERFORM; } old_el = ldb_msg_find_element(old_msg, el->name); - switch (el->flags) { + switch (el->flags & LDB_FLAG_MOD_MASK) { case LDB_FLAG_MOD_REPLACE: ret = replmd_modify_la_replace(module, msg, el, old_el, schema_attr, seq_num, t); break; @@ -1382,6 +1498,24 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, el->flags, el->name); return LDB_ERR_UNWILLING_TO_PERFORM; } + if (ret != LDB_SUCCESS) { + return ret; + } + if (old_el) { + ldb_msg_remove_attr(old_msg, el->name); + } + ldb_msg_add_empty(old_msg, el->name, 0, &new_el); + new_el->num_values = el->num_values; + new_el->values = el->values; + + /* TODO: this relises a bit too heavily on the exact + behaviour of ldb_msg_find_element and + ldb_msg_remove_element */ + old_el = ldb_msg_find_element(msg, el->name); + if (old_el != el) { + ldb_msg_remove_element(msg, old_el); + i--; + } } talloc_free(res); -- cgit From 3b056061ff7f11e70532b859320638f9c8f5f2c7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 11:34:33 +1100 Subject: s4-dsdb: added support for backlinks in repl_meta_data backlinks need more careful handling now that we store the additional meta data for deleted links. It is easier to handle this in repl_meta_data than in linked_attributes. Eventually linked_attributes will disappear, with the functionality moved into repl_meta_data. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 244 ++++++++++++++++++++++-- 1 file changed, 224 insertions(+), 20 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 249dd61a4a..7488a1bee9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -53,6 +53,8 @@ struct replmd_private { TALLOC_CTX *la_ctx; struct la_entry *la_list; + TALLOC_CTX *bl_ctx; + struct la_backlink *la_backlinks; struct nc_entry { struct nc_entry *prev, *next; struct ldb_dn *dn; @@ -87,6 +89,7 @@ struct replmd_replicated_request { static int replmd_replicated_apply_next(struct replmd_replicated_request *ar); + /* initialise the module allocate the private structure and build the list @@ -107,6 +110,169 @@ static int replmd_init(struct ldb_module *module) return ldb_next_init(module); } +/* + cleanup our per-transaction contexts + */ +static void replmd_txn_cleanup(struct replmd_private *replmd_private) +{ + talloc_free(replmd_private->la_ctx); + replmd_private->la_list = NULL; + replmd_private->la_ctx = NULL; + + talloc_free(replmd_private->bl_ctx); + replmd_private->la_backlinks = NULL; + replmd_private->bl_ctx = NULL; +} + + +struct la_backlink { + struct la_backlink *next, *prev; + const char *attr_name; + struct GUID forward_guid, target_guid; + bool active; +}; + +/* + add a backlink to the list of backlinks to add/delete in the prepare + commit + */ +static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema, + struct GUID *forward_guid, struct GUID *target_guid, + bool active, const struct dsdb_attribute *schema_attr) +{ + const struct dsdb_attribute *target_attr; + struct la_backlink *bl; + struct replmd_private *replmd_private = + talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private); + + target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1); + if (!target_attr) { + /* + * windows 2003 has a broken schema where the + * definition of msDS-IsDomainFor is missing (which is + * supposed to be the backlink of the + * msDS-HasDomainNCs attribute + */ + return LDB_SUCCESS; + } + + /* see if its already in the list */ + for (bl=replmd_private->la_backlinks; bl; bl=bl->next) { + if (GUID_equal(forward_guid, &bl->forward_guid) && + GUID_equal(target_guid, &bl->target_guid) && + (target_attr->lDAPDisplayName == bl->attr_name || + strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) { + break; + } + } + + if (bl) { + /* we found an existing one */ + if (bl->active == active) { + return LDB_SUCCESS; + } + DLIST_REMOVE(replmd_private->la_backlinks, bl); + talloc_free(bl); + return LDB_SUCCESS; + } + + if (replmd_private->bl_ctx == NULL) { + replmd_private->bl_ctx = talloc_new(replmd_private); + if (replmd_private->bl_ctx == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + /* its a new one */ + bl = talloc(replmd_private->bl_ctx, struct la_backlink); + if (bl == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + bl->attr_name = target_attr->lDAPDisplayName; + bl->forward_guid = *forward_guid; + bl->target_guid = *target_guid; + bl->active = active; + + DLIST_ADD(replmd_private->la_backlinks, bl); + + return LDB_SUCCESS; +} + +/* + process the list of backlinks we accumulated during + a transaction, adding and deleting the backlinks + from the target objects + */ +static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl) +{ + struct ldb_dn *target_dn, *source_dn; + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_message *msg; + TALLOC_CTX *tmp_ctx = talloc_new(bl); + char *dn_string; + + /* + - find DN of target + - find DN of source + - construct ldb_message + - either an add or a delete + */ + ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n", + GUID_string(bl, &bl->target_guid)); + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n", + GUID_string(bl, &bl->forward_guid)); + talloc_free(tmp_ctx); + return ret; + } + + msg = ldb_msg_new(tmp_ctx); + if (msg == NULL) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* construct a ldb_message for adding/deleting the backlink */ + msg->dn = target_dn; + dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1); + if (!dn_string) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE; + + ret = dsdb_module_modify(module, msg, 0); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s", + bl->active?"add":"remove", + ldb_dn_get_linearized(source_dn), + ldb_dn_get_linearized(target_dn), + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + talloc_free(tmp_ctx); + return ret; +} + /* * Callback for most write operations in this module: @@ -1097,12 +1263,14 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct p handle adding a linked attribute */ static int replmd_modify_la_add(struct ldb_module *module, + struct dsdb_schema *schema, struct ldb_message *msg, struct ldb_message_element *el, struct ldb_message_element *old_el, const struct dsdb_attribute *schema_attr, uint64_t seq_num, - time_t t) + time_t t, + struct GUID *msg_guid) { int i; struct parsed_dn *dns, *old_dns; @@ -1166,6 +1334,12 @@ static int replmd_modify_la_add(struct ldb_module *module, return ret; } } + + ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } /* add the new ones on to the end of the old values, constructing a new el->values */ @@ -1197,12 +1371,14 @@ static int replmd_modify_la_add(struct ldb_module *module, handle deleting all active linked attributes */ static int replmd_modify_la_delete(struct ldb_module *module, + struct dsdb_schema *schema, struct ldb_message *msg, struct ldb_message_element *el, struct ldb_message_element *old_el, const struct dsdb_attribute *schema_attr, uint64_t seq_num, - time_t t) + time_t t, + struct GUID *msg_guid) { int i; struct parsed_dn *dns, *old_dns; @@ -1280,6 +1456,12 @@ static int replmd_modify_la_delete(struct ldb_module *module, talloc_free(tmp_ctx); return ret; } + + ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } el->values = talloc_steal(msg->elements, old_el->values); @@ -1298,12 +1480,14 @@ static int replmd_modify_la_delete(struct ldb_module *module, handle replacing a linked attribute */ static int replmd_modify_la_replace(struct ldb_module *module, + struct dsdb_schema *schema, struct ldb_message *msg, struct ldb_message_element *el, struct ldb_message_element *old_el, const struct dsdb_attribute *schema_attr, uint64_t seq_num, - time_t t) + time_t t, + struct GUID *msg_guid) { int i; struct parsed_dn *dns, *old_dns; @@ -1344,13 +1528,20 @@ static int replmd_modify_la_replace(struct ldb_module *module, struct parsed_dn *p; const struct ldb_val *v; + v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); + if (v) continue; + + ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + p = parsed_dn_find(dns, el->num_values, old_p->guid); if (p) { /* we don't delete it if we are re-adding it */ continue; } - v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); - if (v) continue; ret = replmd_update_la_val(old_el->values, old_p->v, old_p, old_p, invocation_id, seq_num, t, true); @@ -1394,6 +1585,12 @@ static int replmd_modify_la_replace(struct ldb_module *module, } num_new_values++; } + + ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } /* add the new values to the end of old_el */ @@ -1436,6 +1633,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_message *old_msg; struct dsdb_schema *schema = dsdb_get_schema(ldb); + struct GUID old_guid; if (seq_num == 0) { /* there the replmd_update_rpmd code has already @@ -1462,6 +1660,8 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, } old_msg = res->msgs[0]; + old_guid = samdb_result_guid(old_msg, "objectGUID"); + for (i=0; inum_elements; i++) { struct ldb_message_element *el = &msg->elements[i]; struct ldb_message_element *old_el, *new_el; @@ -1484,13 +1684,13 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, old_el = ldb_msg_find_element(old_msg, el->name); switch (el->flags & LDB_FLAG_MOD_MASK) { case LDB_FLAG_MOD_REPLACE: - ret = replmd_modify_la_replace(module, msg, el, old_el, schema_attr, seq_num, t); + ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid); break; case LDB_FLAG_MOD_DELETE: - ret = replmd_modify_la_delete(module, msg, el, old_el, schema_attr, seq_num, t); + ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid); break; case LDB_FLAG_MOD_ADD: - ret = replmd_modify_la_add(module, msg, el, old_el, schema_attr, seq_num, t); + ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid); break; default: ldb_asprintf_errstring(ldb, @@ -2877,9 +3077,7 @@ static int replmd_start_transaction(struct ldb_module *module) /* create our private structure for this transaction */ struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module), struct replmd_private); - talloc_free(replmd_private->la_ctx); - replmd_private->la_list = NULL; - replmd_private->la_ctx = NULL; + replmd_txn_cleanup(replmd_private); /* free any leftover mod_usn records from cancelled transactions */ @@ -2901,6 +3099,7 @@ static int replmd_prepare_commit(struct ldb_module *module) struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module), struct replmd_private); struct la_entry *la, *prev; + struct la_backlink *bl; int ret; /* walk the list backwards, to do the first entry first, as we @@ -2913,16 +3112,22 @@ static int replmd_prepare_commit(struct ldb_module *module) DLIST_REMOVE(replmd_private->la_list, la); ret = replmd_process_linked_attribute(module, la); if (ret != LDB_SUCCESS) { - talloc_free(replmd_private->la_ctx); - replmd_private->la_list = NULL; - replmd_private->la_ctx = NULL; + replmd_txn_cleanup(replmd_private); return ret; } } - talloc_free(replmd_private->la_ctx); - replmd_private->la_list = NULL; - replmd_private->la_ctx = NULL; + /* process our backlink list, creating and deleting backlinks + as necessary */ + for (bl=replmd_private->la_backlinks; bl; bl=bl->next) { + ret = replmd_process_backlink(module, bl); + if (ret != LDB_SUCCESS) { + replmd_txn_cleanup(replmd_private); + return ret; + } + } + + replmd_txn_cleanup(replmd_private); /* possibly change @REPLCHANGED */ ret = replmd_notify_store(module); @@ -2937,9 +3142,8 @@ static int replmd_del_transaction(struct ldb_module *module) { struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module), struct replmd_private); - talloc_free(replmd_private->la_ctx); - replmd_private->la_list = NULL; - replmd_private->la_ctx = NULL; + replmd_txn_cleanup(replmd_private); + return ldb_next_del_trans(module); } -- cgit From c071af337ae0ff11104ca07ea81a7ffa7a8405bc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 11:34:58 +1100 Subject: s4-dsdb: linked_attributes_modify no longer handles modifies This functionality has moved into repl_meta_data --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 183 --------------------- 1 file changed, 183 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index f54693d809..0abec00a71 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -408,188 +408,6 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are } -/* modify */ -static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req) -{ - /* Look over list of modifications */ - /* Find if any are for linked attributes */ - /* Determine the effect of the modification */ - /* Apply the modify to the linked entry */ - - struct ldb_context *ldb; - int i, j; - struct la_context *ac; - struct ldb_request *search_req; - const char **attrs; - - int ret; - - ldb = ldb_module_get_ctx(module); - - if (ldb_dn_is_special(req->op.mod.message->dn)) { - /* do not manipulate our control entries */ - return ldb_next_request(module, req); - } - - ac = linked_attributes_init(module, req); - if (!ac) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (!ac->schema) { - /* without schema, this doesn't make any sense */ - return ldb_next_request(module, req); - } - - ac->rc = talloc_zero(ac, struct replace_context); - if (!ac->rc) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - for (i=0; i < req->op.mod.message->num_elements; i++) { - bool store_el = false; - const char *attr_name; - const struct dsdb_attribute *target_attr; - const struct ldb_message_element *el = &req->op.mod.message->elements[i]; - const struct dsdb_attribute *schema_attr - = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name); - if (!schema_attr) { - ldb_asprintf_errstring(ldb, - "attribute %s is not a valid attribute in schema", el->name); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } - /* We have a valid attribute, now find out if it is linked */ - if (schema_attr->linkID == 0) { - continue; - } - - if ((schema_attr->linkID & 1) == 1) { - /* Odd is for the target. Illegal to modify */ - ldb_asprintf_errstring(ldb, - "attribute %s must not be modified directly, it is a linked attribute", el->name); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - - /* Even link IDs are for the originating attribute */ - - /* Now find the target attribute */ - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1); - if (!target_attr) { - /* - * windows 2003 has a broken schema where - * the definition of msDS-IsDomainFor - * is missing (which is supposed to be - * the backlink of the msDS-HasDomainNCs - * attribute - */ - continue; - } - - attr_name = target_attr->lDAPDisplayName; - - switch (el->flags & LDB_FLAG_MOD_MASK) { - case LDB_FLAG_MOD_REPLACE: - /* treat as just a normal add the delete part is handled by the callback */ - store_el = true; - - /* break intentionally missing */ - - case LDB_FLAG_MOD_ADD: - - /* For each value being added, we need to setup the adds */ - for (j = 0; j < el->num_values; j++) { - ret = la_store_op(ac, LA_OP_ADD, - &el->values[j], - attr_name); - if (ret != LDB_SUCCESS) { - return ret; - } - } - break; - - case LDB_FLAG_MOD_DELETE: - - if (el->num_values) { - /* For each value being deleted, we need to setup the delete */ - for (j = 0; j < el->num_values; j++) { - ret = la_store_op(ac, LA_OP_DEL, - &el->values[j], - attr_name); - if (ret != LDB_SUCCESS) { - return ret; - } - } - } else { - /* Flag that there was a DELETE - * without a value specified, so we - * need to look for the old value */ - store_el = true; - } - - break; - } - - if (store_el) { - struct ldb_message_element *search_el; - - search_el = talloc_realloc(ac->rc, ac->rc->el, - struct ldb_message_element, - ac->rc->num_elements +1); - if (!search_el) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - ac->rc->el = search_el; - - ac->rc->el[ac->rc->num_elements] = *el; - ac->rc->num_elements++; - } - } - - if (ac->ops || ac->rc->el) { - /* both replace and delete without values are handled in the callback - * after the search on the entry to be modified is performed */ - - attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1); - if (!attrs) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - for (i = 0; ac->rc && i < ac->rc->num_elements; i++) { - attrs[i] = ac->rc->el[i].name; - } - attrs[i] = NULL; - - /* The callback does all the hard work here */ - ret = ldb_build_search_req(&search_req, ldb, ac, - req->op.mod.message->dn, - LDB_SCOPE_BASE, - "(objectClass=*)", attrs, - NULL, - ac, la_mod_search_callback, - req); - - /* We need to figure out our own extended DN, to fill in as the backlink target */ - if (ret == LDB_SUCCESS) { - ret = ldb_request_add_control(search_req, - LDB_CONTROL_EXTENDED_DN_OID, - false, NULL); - } - if (ret == LDB_SUCCESS) { - talloc_steal(search_req, attrs); - - ret = ldb_next_request(module, search_req); - } - - } else { - /* nothing to do for this module, proceed */ - talloc_free(ac); - ret = ldb_next_request(module, req); - } - - return ret; -} /* delete */ static int linked_attributes_del(struct ldb_module *module, struct ldb_request *req) @@ -1250,7 +1068,6 @@ static int linked_attributes_del_transaction(struct ldb_module *module) _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = { .name = "linked_attributes", .add = linked_attributes_add, - .modify = linked_attributes_modify, .del = linked_attributes_del, .rename = linked_attributes_rename, .start_transaction = linked_attributes_start_transaction, -- cgit From 3199e02884af3b14348a88e8d8d7bc852212536f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 12:01:51 +1100 Subject: s4-dsdb: add a comment on the use of ldb_rename() We need to use ldb_rename() and not dsdb_module_rename() here as we need the rename to be processed by the current module --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 7488a1bee9..dadaf32f80 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2078,6 +2078,9 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n", ldb_dn_get_linearized(ar->search_msg->dn), ldb_dn_get_linearized(msg->dn)); + /* we can't use dsdb_module_rename() here as we need + the rename call to be intercepted by this module, to + allow it to process linked attribute changes */ if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n", ldb_dn_get_linearized(ar->search_msg->dn), -- cgit From bd5678f4bebad82f1b949931049bbd8496616777 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 17:14:26 +1100 Subject: s4-dsdb: repl_meta_data now replaces objectguid in all cases We don't want to be debugging two different code paths through the ldb module stack, so better to always do the work of repl_meta_data, even for a standalone server Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/samba_dsdb.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c index bfa2599afe..a461a94806 100644 --- a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c +++ b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c @@ -234,16 +234,11 @@ static int samba_dsdb_init(struct ldb_module *module) "instancetype", NULL }; - const char *objectguid_module; - /* if serverrole == "domain controller": */ - const char *repl_meta_data = "repl_meta_data"; - /* else: */ - const char *objectguid = "objectguid"; - const char **link_modules; static const char *tdb_modules_list[] = { - "subtree_rename", "subtree_delete", + "repl_meta_data", + "subtree_rename", "linked_attributes", NULL}; @@ -328,15 +323,9 @@ static int samba_dsdb_init(struct ldb_module *module) backend_modules = NULL; if (strcasecmp(backendType, "ldb") == 0) { - if (strcasecmp(serverRole, "dc") == 0 || strcasecmp(serverRole, "domain controller") == 0) { - objectguid_module = repl_meta_data; - } else { - objectguid_module = objectguid; - } extended_dn_module = extended_dn_module_ldb; link_modules = tdb_modules_list; } else { - objectguid_module = NULL; link_modules = NULL; if (strcasecmp(backendType, "fedora-ds") == 0) { backend_modules = fedora_ds_backend_modules; @@ -359,9 +348,6 @@ static int samba_dsdb_init(struct ldb_module *module) final_module_list = str_list_copy_const(tmp_ctx, modules_list); CHECK_MODULE_LIST; - final_module_list = str_list_add_const(final_module_list, objectguid_module); - CHECK_MODULE_LIST; - final_module_list = str_list_append_const(final_module_list, link_modules); CHECK_MODULE_LIST; -- cgit From 5964acfa741d691c0196f91c0796122ec025f177 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 17:15:23 +1100 Subject: s4-dsdb: the linked_attributes module no longer handles deletes delete handling is now moved into repl_meta_data Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 53 ---------------------- 1 file changed, 53 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 0abec00a71..81c6ec90af 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -409,57 +409,6 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are -/* delete */ -static int linked_attributes_del(struct ldb_module *module, struct ldb_request *req) -{ - struct ldb_context *ldb; - struct ldb_request *search_req; - struct la_context *ac; - const char **attrs; - WERROR werr; - int ret; - - /* This gets complex: We need to: - - Do a search for the entry - - Wait for these result to appear - - In the callback for the result, issue a modify - request based on the linked attributes found - - Wait for each modify result - - Regain our sainity - */ - - ldb = ldb_module_get_ctx(module); - - ac = linked_attributes_init(module, req); - if (!ac) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (!ac->schema) { - /* without schema, this doesn't make any sense */ - return ldb_next_request(module, req); - } - - werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs); - if (!W_ERROR_IS_OK(werr)) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = ldb_build_search_req(&search_req, ldb, req, - req->op.del.dn, LDB_SCOPE_BASE, - "(objectClass=*)", attrs, - NULL, - ac, la_op_search_callback, - req); - - if (ret != LDB_SUCCESS) { - return ret; - } - - talloc_steal(search_req, attrs); - - return ldb_next_request(module, search_req); -} /* rename */ static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req) @@ -1068,8 +1017,6 @@ static int linked_attributes_del_transaction(struct ldb_module *module) _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = { .name = "linked_attributes", .add = linked_attributes_add, - .del = linked_attributes_del, - .rename = linked_attributes_rename, .start_transaction = linked_attributes_start_transaction, .prepare_commit = linked_attributes_prepare_commit, .del_transaction = linked_attributes_del_transaction, -- cgit From 348bcfc8ff81a95ff2f1785ba4efdaf2e8a193a4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 17:24:21 +1100 Subject: s4-dsdb: added replmd_delete, based on Eduardos work This implements repmld_delete(), which handles the meta_data updates for an object when deleting. A delete gets mapped to a combination of a rename followed by a modify request, which has the effect of moving the object into the Deleted Objects container. This is based on the code from Eduardo Lima . Eduardo's code was modified to take account of the linked attributes changes that Andrew and I have been working on. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 295 ++++++++++++++++++++++++ 1 file changed, 295 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index dadaf32f80..2a7f472046 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1914,6 +1914,300 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are return ldb_next_request(ac->module, down_req); } +/* remove forwards and backlinks as needed when an object + is deleted */ +static int replmd_delete_remove_link(struct ldb_module *module, + struct dsdb_schema *schema, + struct ldb_dn *dn, + struct ldb_message_element *el, + const struct dsdb_attribute *sa) +{ + int i; + TALLOC_CTX *tmp_ctx = talloc_new(module); + struct ldb_context *ldb = ldb_module_get_ctx(module); + + for (i=0; inum_values; i++) { + struct dsdb_dn *dsdb_dn; + const struct ldb_val *v; + NTSTATUS status; + int ret; + struct GUID guid2; + struct ldb_message *msg; + const struct dsdb_attribute *target_attr; + struct ldb_message_element *el2; + struct ldb_val dn_val; + + if (dsdb_dn_is_deleted_val(&el->values[i])) { + continue; + } + + dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid); + if (!dsdb_dn) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + v = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID"); + if (!v) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + status = GUID_from_ndr_blob(v, &guid2); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* remove the link */ + msg = ldb_msg_new(tmp_ctx); + if (!msg) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + + msg->dn = dsdb_dn->dn; + + if (sa->linkID & 1) { + target_attr = dsdb_attribute_by_linkID(schema, sa->linkID - 1); + } else { + target_attr = dsdb_attribute_by_linkID(schema, sa->linkID + 1); + } + + ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2); + if (ret != LDB_SUCCESS) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + dn_val = data_blob_string_const(ldb_dn_get_linearized(dn)); + el2->values = &dn_val; + el2->num_values = 1; + + ret = dsdb_module_modify(module, msg, 0); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + + +/* + handle update of replication meta data for deletion of objects + + This also handles the mapping of delete to a rename operation + to allow deletes to be replicated. + */ +static int replmd_delete(struct ldb_module *module, struct ldb_request *req) +{ + int ret = LDB_ERR_OTHER; + bool retb; + struct ldb_dn *old_dn, *new_dn; + const char *rdn_name; + const struct ldb_val *rdn_value, *new_rdn_value; + struct GUID guid; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_schema *schema = dsdb_get_schema(ldb); + struct ldb_message *msg, *old_msg; + struct ldb_message_element *el; + TALLOC_CTX *tmp_ctx; + struct ldb_result *res, *parent_res; + const char *preserved_attrs[] = { + /* yes, this really is a hard coded list. See MS-ADTS + section 3.1.1.5.5.1.1 */ + "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName", + "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN", + "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID", + "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid", + "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName", + "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection", + "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreate", + NULL}; + uint32_t el_count = 0; + int i; + + tmp_ctx = talloc_new(ldb); + + old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn); + + /* we need the complete msg off disk, so we can work out which + attributes need to be removed */ + ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL, + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_REVEAL_INTERNALS | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + old_msg = res->msgs[0]; + + /* work out where we will be renaming this object to */ + ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn); + if (ret != LDB_SUCCESS) { + /* this is probably an attempted delete on a partition + * that doesn't allow delete operations, such as the + * schema partition */ + ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s", + ldb_dn_get_linearized(old_dn)); + talloc_free(tmp_ctx); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + rdn_name = ldb_dn_get_rdn_name(old_dn); + rdn_value = ldb_dn_get_rdn_val(old_dn); + + /* get the objects GUID from the search we just did */ + guid = samdb_result_guid(old_msg, "objectGUID"); + + /* Add a formatted child */ + retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s", + rdn_name, + rdn_value->data, + GUID_string(tmp_ctx, &guid)); + if (!retb) { + DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s", + ldb_dn_get_linearized(new_dn))); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* New DN name generated, renaming the original DN */ + ret = dsdb_module_rename(module, old_dn, new_dn, 0); + if (ret != LDB_SUCCESS){ + DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s'\n", + ldb_dn_get_linearized(old_dn), + ldb_dn_get_linearized(new_dn))); + talloc_free(tmp_ctx); + return ret; + } + + /* + now we need to modify the object in the following ways: + + - add isDeleted=TRUE + - update rDN and name, with new rDN + - remove linked attributes + - remove objectCategory and sAMAccountType + - remove attribs not on the preserved list + - preserved if in above list, or is rDN + - remove all linked attribs from this object + - remove all links from other objects to this object + - add lastKnownParent + - update replPropertyMetaData? + + see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1 + */ + + msg = ldb_msg_new(tmp_ctx); + if (msg == NULL) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->dn = new_dn; + + ret = ldb_msg_add_string(msg, "isDeleted", "TRUE"); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n")); + ldb_module_oom(module); + talloc_free(tmp_ctx); + return ret; + } + msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD; + + /* we need the storage form of the parent GUID */ + ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res, + ldb_dn_get_parent(tmp_ctx, old_dn), NULL, + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = ldb_msg_add_steal_string(msg, "lastKnownParent", + ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1)); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n")); + ldb_module_oom(module); + talloc_free(tmp_ctx); + return ret; + } + msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD; + + /* work out which of the old attributes we will be removing */ + for (i=0; inum_elements; i++) { + const struct dsdb_attribute *sa; + el = &old_msg->elements[i]; + sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name); + if (!sa) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + if (ldb_attr_cmp(el->name, rdn_name) == 0) { + /* don't remove the rDN */ + continue; + } + + if (sa->linkID) { + ret = replmd_delete_remove_link(module, schema, old_dn, el, sa); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) { + continue; + } + + ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + ldb_module_oom(module); + return ret; + } + } + + /* work out what the new rdn value is, for updating the + rDN and name fields */ + new_rdn_value = ldb_dn_get_rdn_val(new_dn); + ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + el->flags = LDB_FLAG_MOD_REPLACE; + + el = ldb_msg_find_element(old_msg, "name"); + if (el) { + ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + el->flags = LDB_FLAG_MOD_REPLACE; + } + + ret = dsdb_module_modify(module, msg, 0); + if (ret != LDB_SUCCESS){ + ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s", + ldb_dn_get_linearized(old_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + talloc_free(tmp_ctx); + + return ldb_module_done(req, NULL, NULL, LDB_SUCCESS); +} + + static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret) { @@ -3157,6 +3451,7 @@ _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = { .add = replmd_add, .modify = replmd_modify, .rename = replmd_rename, + .del = replmd_delete, .extended = replmd_extended, .start_transaction = replmd_start_transaction, .prepare_commit = replmd_prepare_commit, -- cgit From 9e96ae8ddc49e146323e9a44d38f725f4a5fb663 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 10:42:15 +1100 Subject: s4-dsdb: add linked attributes meta_data handling to replmd_add This also handles the backlink creation that was previously in the linked_attributes module Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 110 ++++++++++++++++++------ 1 file changed, 86 insertions(+), 24 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 2a7f472046..245560f769 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -572,6 +572,59 @@ static void replmd_ldb_message_sort(struct ldb_message *msg, discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort); } +static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, + const struct GUID *invocation_id, uint64_t seq_num, time_t t); + +/* + fix up linked attributes in replmd_add. + This involves setting up the right meta-data in extended DN + components, and creating backlinks to the object + */ +static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el, + uint64_t seq_num, const struct GUID *invocationId, time_t t, + struct GUID *guid, const struct dsdb_attribute *sa) +{ + int i; + TALLOC_CTX *tmp_ctx = talloc_new(el->values); + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_schema *schema = dsdb_get_schema(ldb); + + for (i=0; inum_values; i++) { + struct ldb_val *v = &el->values[i]; + struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid); + struct GUID target_guid; + NTSTATUS status; + int ret; + + ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, seq_num, t); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + /* note that the DN already has the extended + components from the extended_dn_store module */ + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + + +/* + intercept add requests + */ static int replmd_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; @@ -728,6 +781,19 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) continue; } +#if W2K3_LINKED_ATTRIBUTES + if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) { + ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa); + if (ret != LDB_SUCCESS) { + talloc_free(ac); + return ret; + } + /* linked attributes are not stored in + replPropertyMetaData in FL above w2k */ + continue; + } +#endif + m->attid = sa->attributeID_id; m->version = 1; m->originating_change_time = now; @@ -1106,10 +1172,10 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, RMD_USN = originating_usn RMD_VERSION = version */ -static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p, +static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, time_t t) { - struct ldb_dn *dn = p->dsdb_dn->dn; + struct ldb_dn *dn = dsdb_dn->dn; NTTIME now; const char *tstring, *usn_string; struct ldb_val tval; @@ -1153,7 +1219,7 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct pa ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); if (ret != LDB_SUCCESS) return ret; - dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1); + dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1); if (dnstring == NULL) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1168,11 +1234,11 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct pa see replmd_build_la_val for value names */ -static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p, - struct parsed_dn *old_p, const struct GUID *invocation_id, +static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, + struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, time_t t, bool deleted) { - struct ldb_dn *dn = p->dsdb_dn->dn; + struct ldb_dn *dn = dsdb_dn->dn; NTTIME now; const char *tstring, *usn_string; struct ldb_val tval; @@ -1212,11 +1278,11 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct p if (ret != LDB_SUCCESS) return ret; /* get the ADDTIME from the original */ - old_addtime = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_ADDTIME"); + old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME"); if (old_addtime == NULL) { old_addtime = &tval; } - if (p != old_p) { + if (dsdb_dn != old_dsdb_dn) { ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime); if (ret != LDB_SUCCESS) return ret; } @@ -1234,7 +1300,7 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct p if (ret != LDB_SUCCESS) return ret; /* increase the version by 1 */ - old_version = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_VERSION"); + old_version = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_VERSION"); if (old_version == NULL) { vers = data_blob_string_const("0"); } else { @@ -1250,7 +1316,7 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct p ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); if (ret != LDB_SUCCESS) return ret; - dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1); + dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1); if (dnstring == NULL) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1310,7 +1376,7 @@ static int replmd_modify_la_add(struct ldb_module *module, talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } - ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i], + ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, invocation_id, seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -1328,7 +1394,8 @@ static int replmd_modify_la_add(struct ldb_module *module, talloc_free(tmp_ctx); return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; } - ret = replmd_update_la_val(old_el->values, p->v, &dns[i], p, invocation_id, seq_num, t, false); + ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn, + invocation_id, seq_num, t, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1451,7 +1518,8 @@ static int replmd_modify_la_delete(struct ldb_module *module, v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); if (v != NULL) continue; - ret = replmd_update_la_val(old_el->values, p->v, p, p, invocation_id, seq_num, t, true); + ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn, + invocation_id, seq_num, t, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1543,7 +1611,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, continue; } - ret = replmd_update_la_val(old_el->values, old_p->v, old_p, old_p, + ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, invocation_id, seq_num, t, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -1561,8 +1629,8 @@ static int replmd_modify_la_replace(struct ldb_module *module, (old_p = parsed_dn_find(old_dns, old_num_values, p->guid)) != NULL) { /* update in place */ - ret = replmd_update_la_val(old_el->values, old_p->v, old_p, - old_p, invocation_id, + ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, + old_p->dsdb_dn, invocation_id, seq_num, t, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -1577,7 +1645,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } - ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i], + ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, invocation_id, seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -1928,7 +1996,6 @@ static int replmd_delete_remove_link(struct ldb_module *module, for (i=0; inum_values; i++) { struct dsdb_dn *dsdb_dn; - const struct ldb_val *v; NTSTATUS status; int ret; struct GUID guid2; @@ -1947,12 +2014,7 @@ static int replmd_delete_remove_link(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } - v = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID"); - if (!v) { - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } - status = GUID_from_ndr_blob(v, &guid2); + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; -- cgit From 3fe9244796cea72abe8d7ec4ce54acf45ee2da48 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 10:42:44 +1100 Subject: s4-dsdb: remove linked_attributes_add This is now handled in the repl_meta_data module --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 86 ---------------------- 1 file changed, 86 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 81c6ec90af..2ea5024431 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -196,91 +196,6 @@ static int la_down_req(struct la_context *ac); -/* add */ -static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req) -{ - struct ldb_context *ldb; - const struct dsdb_attribute *target_attr; - struct la_context *ac; - const char *attr_name; - int ret; - int i, j; - - ldb = ldb_module_get_ctx(module); - - if (ldb_dn_is_special(req->op.add.message->dn)) { - /* do not manipulate our control entries */ - return ldb_next_request(module, req); - } - - ac = linked_attributes_init(module, req); - if (!ac) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (!ac->schema) { - /* without schema, this doesn't make any sense */ - talloc_free(ac); - return ldb_next_request(module, req); - } - - /* Need to ensure we only have forward links being specified */ - for (i=0; i < req->op.add.message->num_elements; i++) { - const struct ldb_message_element *el = &req->op.add.message->elements[i]; - const struct dsdb_attribute *schema_attr - = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name); - if (!schema_attr) { - ldb_asprintf_errstring(ldb, - "attribute %s is not a valid attribute in schema", el->name); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } - /* We have a valid attribute, now find out if it is linked */ - if (schema_attr->linkID == 0) { - continue; - } - - if ((schema_attr->linkID & 1) == 1) { - /* Odd is for the target. Illegal to modify */ - ldb_asprintf_errstring(ldb, - "attribute %s must not be modified directly, it is a linked attribute", el->name); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - - /* Even link IDs are for the originating attribute */ - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1); - if (!target_attr) { - /* - * windows 2003 has a broken schema where - * the definition of msDS-IsDomainFor - * is missing (which is supposed to be - * the backlink of the msDS-HasDomainNCs - * attribute - */ - continue; - } - - attr_name = target_attr->lDAPDisplayName; - - for (j = 0; j < el->num_values; j++) { - ret = la_store_op(ac, LA_OP_ADD, - &el->values[j], - attr_name); - if (ret != LDB_SUCCESS) { - return ret; - } - } - } - - /* if no linked attributes are present continue */ - if (ac->ops == NULL) { - /* nothing to do for this module, proceed */ - talloc_free(ac); - return ldb_next_request(module, req); - } - - /* start with the original request */ - return la_down_req(ac); -} /* For a delete or rename, we need to find out what linked attributes * are currently on this DN, and then deal with them. This is the @@ -1016,7 +931,6 @@ static int linked_attributes_del_transaction(struct ldb_module *module) _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = { .name = "linked_attributes", - .add = linked_attributes_add, .start_transaction = linked_attributes_start_transaction, .prepare_commit = linked_attributes_prepare_commit, .del_transaction = linked_attributes_del_transaction, -- cgit From 2b5cd3dba29043281a6ca04398623a7f1972d71b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 10:50:34 +1100 Subject: s4-dsdb: some backlinks can be processed immediately backlinks in add and delete operations can be processed immediately, rather than at the end of a transaction. This can save on backlink list processing time. --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 161 ++++++++++++------------ 1 file changed, 84 insertions(+), 77 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 245560f769..3390f80f13 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -133,78 +133,8 @@ struct la_backlink { }; /* - add a backlink to the list of backlinks to add/delete in the prepare - commit - */ -static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema, - struct GUID *forward_guid, struct GUID *target_guid, - bool active, const struct dsdb_attribute *schema_attr) -{ - const struct dsdb_attribute *target_attr; - struct la_backlink *bl; - struct replmd_private *replmd_private = - talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private); - - target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1); - if (!target_attr) { - /* - * windows 2003 has a broken schema where the - * definition of msDS-IsDomainFor is missing (which is - * supposed to be the backlink of the - * msDS-HasDomainNCs attribute - */ - return LDB_SUCCESS; - } - - /* see if its already in the list */ - for (bl=replmd_private->la_backlinks; bl; bl=bl->next) { - if (GUID_equal(forward_guid, &bl->forward_guid) && - GUID_equal(target_guid, &bl->target_guid) && - (target_attr->lDAPDisplayName == bl->attr_name || - strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) { - break; - } - } - - if (bl) { - /* we found an existing one */ - if (bl->active == active) { - return LDB_SUCCESS; - } - DLIST_REMOVE(replmd_private->la_backlinks, bl); - talloc_free(bl); - return LDB_SUCCESS; - } - - if (replmd_private->bl_ctx == NULL) { - replmd_private->bl_ctx = talloc_new(replmd_private); - if (replmd_private->bl_ctx == NULL) { - ldb_module_oom(module); - return LDB_ERR_OPERATIONS_ERROR; - } - } - - /* its a new one */ - bl = talloc(replmd_private->bl_ctx, struct la_backlink); - if (bl == NULL) { - ldb_module_oom(module); - return LDB_ERR_OPERATIONS_ERROR; - } - - bl->attr_name = target_attr->lDAPDisplayName; - bl->forward_guid = *forward_guid; - bl->target_guid = *target_guid; - bl->active = active; - - DLIST_ADD(replmd_private->la_backlinks, bl); - - return LDB_SUCCESS; -} - -/* - process the list of backlinks we accumulated during - a transaction, adding and deleting the backlinks - from the target objects + process a backlinks we accumulated during a transaction, adding and + deleting the backlinks from the target objects */ static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl) { @@ -273,6 +203,83 @@ static int replmd_process_backlink(struct ldb_module *module, struct la_backlink return ret; } +/* + add a backlink to the list of backlinks to add/delete in the prepare + commit + */ +static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema, + struct GUID *forward_guid, struct GUID *target_guid, + bool active, const struct dsdb_attribute *schema_attr, bool immediate) +{ + const struct dsdb_attribute *target_attr; + struct la_backlink *bl; + struct replmd_private *replmd_private = + talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private); + + target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1); + if (!target_attr) { + /* + * windows 2003 has a broken schema where the + * definition of msDS-IsDomainFor is missing (which is + * supposed to be the backlink of the + * msDS-HasDomainNCs attribute + */ + return LDB_SUCCESS; + } + + /* see if its already in the list */ + for (bl=replmd_private->la_backlinks; bl; bl=bl->next) { + if (GUID_equal(forward_guid, &bl->forward_guid) && + GUID_equal(target_guid, &bl->target_guid) && + (target_attr->lDAPDisplayName == bl->attr_name || + strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) { + break; + } + } + + if (bl) { + /* we found an existing one */ + if (bl->active == active) { + return LDB_SUCCESS; + } + DLIST_REMOVE(replmd_private->la_backlinks, bl); + talloc_free(bl); + return LDB_SUCCESS; + } + + if (replmd_private->bl_ctx == NULL) { + replmd_private->bl_ctx = talloc_new(replmd_private); + if (replmd_private->bl_ctx == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + /* its a new one */ + bl = talloc(replmd_private->bl_ctx, struct la_backlink); + if (bl == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + bl->attr_name = target_attr->lDAPDisplayName; + bl->forward_guid = *forward_guid; + bl->target_guid = *target_guid; + bl->active = active; + + /* the caller may ask for this backlink to be processed + immediately */ + if (immediate) { + int ret = replmd_process_backlink(module, bl); + talloc_free(bl); + return ret; + } + + DLIST_ADD(replmd_private->la_backlinks, bl); + + return LDB_SUCCESS; +} + /* * Callback for most write operations in this module: @@ -610,7 +617,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme return LDB_ERR_OPERATIONS_ERROR; } - ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa); + ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1402,7 +1409,7 @@ static int replmd_modify_la_add(struct ldb_module *module, } } - ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr); + ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1525,7 +1532,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, return ret; } - ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr); + ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1599,7 +1606,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); if (v) continue; - ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr); + ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1654,7 +1661,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, num_new_values++; } - ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr); + ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; -- cgit From e9699e9cb9c2a5dc43a85c3d1565e12e0e299038 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 23:00:16 +1100 Subject: s4-dsdb: do the rename after the modify in replmd_delete This makes updating the links a bit easier --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3390f80f13..689b24f398 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -617,7 +617,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme return LDB_ERR_OPERATIONS_ERROR; } - ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, true); + ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2145,16 +2145,6 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - /* New DN name generated, renaming the original DN */ - ret = dsdb_module_rename(module, old_dn, new_dn, 0); - if (ret != LDB_SUCCESS){ - DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s'\n", - ldb_dn_get_linearized(old_dn), - ldb_dn_get_linearized(new_dn))); - talloc_free(tmp_ctx); - return ret; - } - /* now we need to modify the object in the following ways: @@ -2179,7 +2169,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - msg->dn = new_dn; + msg->dn = old_dn; ret = ldb_msg_add_string(msg, "isDeleted", "TRUE"); if (ret != LDB_SUCCESS) { @@ -2271,6 +2261,17 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) return ret; } + /* now rename onto the new DN */ + ret = dsdb_module_rename(module, old_dn, new_dn, 0); + if (ret != LDB_SUCCESS){ + DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n", + ldb_dn_get_linearized(old_dn), + ldb_dn_get_linearized(new_dn), + ldb_errstring(ldb))); + talloc_free(tmp_ctx); + return ret; + } + talloc_free(tmp_ctx); return ldb_module_done(req, NULL, NULL, LDB_SUCCESS); -- cgit From 5eefff915e0c49cbdbecd764b8e0a2cc15d10d93 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 23:02:08 +1100 Subject: s4-dsdb: simplify the linked_attributes module The linked_attributes module only has to deal with renames now, as other linked attribute updates happen in repl_meta_data. This allows it to be much simpler. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 949 +++------------------ 1 file changed, 96 insertions(+), 853 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 2ea5024431..edcb2d8167 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -33,905 +33,148 @@ #include "dlinklist.h" #include "dsdb/samdb/samdb.h" #include "librpc/gen_ndr/ndr_misc.h" - -struct la_private { - struct la_context *la_list; -}; - -struct la_op_store { - struct la_op_store *next; - struct la_op_store *prev; - enum la_op {LA_OP_ADD, LA_OP_DEL} op; - struct GUID guid; - char *name; - char *value; -}; - -struct replace_context { - struct la_context *ac; - unsigned int num_elements; - struct ldb_message_element *el; -}; - -struct la_context { - struct la_context *next, *prev; - const struct dsdb_schema *schema; - struct ldb_module *module; - struct ldb_request *req; - struct ldb_dn *partition_dn; - struct ldb_dn *add_dn; - struct ldb_dn *del_dn; - struct replace_context *rc; - struct la_op_store *ops; - struct ldb_extended *op_response; - struct ldb_control **op_controls; -}; - -static struct la_context *linked_attributes_init(struct ldb_module *module, - struct ldb_request *req) -{ - struct ldb_context *ldb; - struct la_context *ac; - const struct ldb_control *partition_ctrl; - - ldb = ldb_module_get_ctx(module); - - ac = talloc_zero(req, struct la_context); - if (ac == NULL) { - ldb_oom(ldb); - return NULL; - } - - ac->schema = dsdb_get_schema(ldb); - ac->module = module; - ac->req = req; - - /* remember the partition DN that came in, if given */ - partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID); - if (partition_ctrl) { - const struct dsdb_control_current_partition *partition; - partition = talloc_get_type(partition_ctrl->data, - struct dsdb_control_current_partition); - SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION); - - ac->partition_dn = ldb_dn_copy(ac, partition->dn); - } - - return ac; -} - -/* - turn a DN into a GUID - */ -static int la_guid_from_dn(struct la_context *ac, struct ldb_dn *dn, struct GUID *guid) -{ - int ret; - NTSTATUS status; - - status = dsdb_get_extended_dn_guid(dn, guid); - if (NT_STATUS_IS_OK(status)) { - return LDB_SUCCESS; - } - if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { - DEBUG(4,(__location__ ": Unable to parse GUID for dn %s\n", - ldb_dn_get_linearized(dn))); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = dsdb_find_guid_by_dn(ldb_module_get_ctx(ac->module), dn, guid); - if (ret != LDB_SUCCESS) { - DEBUG(4,(__location__ ": Failed to find GUID for dn %s\n", - ldb_dn_get_linearized(dn))); - return ret; - } - return LDB_SUCCESS; -} +#include "dsdb/samdb/ldb_modules/util.h" -/* Common routine to handle reading the attributes and creating a - * series of modify requests */ -static int la_store_op(struct la_context *ac, - enum la_op op, struct ldb_val *dn, - const char *name) +static int linked_attributes_fix_links(struct ldb_module *module, + struct ldb_dn *old_dn, struct ldb_dn *new_dn, + struct ldb_message_element *el, struct dsdb_schema *schema, + const struct dsdb_attribute *schema_attr) { - struct ldb_context *ldb; - struct la_op_store *os; - struct ldb_dn *op_dn; - int ret; + int i; + TALLOC_CTX *tmp_ctx = talloc_new(module); + struct ldb_context *ldb = ldb_module_get_ctx(module); + const struct dsdb_attribute *target; + const char *attrs[2]; - ldb = ldb_module_get_ctx(ac->module); - - op_dn = ldb_dn_from_ldb_val(ac, ldb, dn); - if (!op_dn) { - ldb_asprintf_errstring(ldb, - "could not parse attribute as a DN"); - return LDB_ERR_INVALID_DN_SYNTAX; - } - - os = talloc_zero(ac, struct la_op_store); - if (!os) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - os->op = op; - - ret = la_guid_from_dn(ac, op_dn, &os->guid); - if (ret == LDB_ERR_NO_SUCH_OBJECT && ac->req->operation == LDB_DELETE) { - /* we are deleting an object, and we've found it has a - * forward link to a target that no longer - * exists. This is not an error in the delete, and we - * should just not do the deferred delete of the - * target attribute - */ - talloc_free(os); + target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1); + if (target == NULL) { + /* there is no counterpart link to change */ return LDB_SUCCESS; } - if (ret != LDB_SUCCESS) { - return ret; - } - - os->name = talloc_strdup(os, name); - if (!os->name) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - /* Do deletes before adds */ - if (op == LA_OP_ADD) { - DLIST_ADD_END(ac->ops, os, struct la_op_store *); - } else { - /* By adding to the head of the list, we do deletes before - * adds when processing a replace */ - DLIST_ADD(ac->ops, os); - } - - return LDB_SUCCESS; -} -static int la_op_search_callback(struct ldb_request *req, - struct ldb_reply *ares); -static int la_queue_mod_request(struct la_context *ac); -static int la_down_req(struct la_context *ac); + attrs[0] = target->lDAPDisplayName; + attrs[1] = NULL; + for (i=0; inum_values; i++) { + struct dsdb_dn *dsdb_dn; + int ret, j; + struct ldb_result *res; + struct ldb_message *msg; + struct ldb_message_element *el2; - - -/* For a delete or rename, we need to find out what linked attributes - * are currently on this DN, and then deal with them. This is the - * callback to the base search */ - -static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - struct ldb_context *ldb; - const struct dsdb_attribute *schema_attr; - const struct dsdb_attribute *target_attr; - struct ldb_message_element *search_el; - struct replace_context *rc; - struct la_context *ac; - const char *attr_name; - int i, j; - int ret = LDB_SUCCESS; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - rc = ac->rc; - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - /* Only entries are interesting, and we only want the olddn */ - switch (ares->type) { - case LDB_REPLY_ENTRY: - - if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) { - ldb_asprintf_errstring(ldb, - "linked_attributes: %s is not the DN we were looking for", ldb_dn_get_linearized(ares->message->dn)); - /* Guh? We only asked for this DN */ - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); + dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid); + if (dsdb_dn == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_INVALID_DN_SYNTAX; } - ac->add_dn = ac->del_dn = talloc_steal(ac, ares->message->dn); - - /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */ - for (i = 0; rc && i < rc->num_elements; i++) { - - schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name); - if (!schema_attr) { - ldb_asprintf_errstring(ldb, - "attribute %s is not a valid attribute in schema", - rc->el[i].name); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OBJECT_CLASS_VIOLATION); - } - - search_el = ldb_msg_find_element(ares->message, - rc->el[i].name); - - /* See if this element already exists */ - /* otherwise just ignore as - * the add has already been scheduled */ - if ( ! search_el) { - continue; - } - - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1); - if (!target_attr) { - /* - * windows 2003 has a broken schema where - * the definition of msDS-IsDomainFor - * is missing (which is supposed to be - * the backlink of the msDS-HasDomainNCs - * attribute - */ - continue; - } - attr_name = target_attr->lDAPDisplayName; - - /* Now we know what was there, we can remove it for the re-add */ - for (j = 0; j < search_el->num_values; j++) { - ret = la_store_op(ac, LA_OP_DEL, - &search_el->values[j], - attr_name); - if (ret != LDB_SUCCESS) { - talloc_free(ares); - return ldb_module_done(ac->req, - NULL, NULL, ret); - } - } - } - - break; - - case LDB_REPLY_REFERRAL: - /* ignore */ - break; - - case LDB_REPLY_DONE: - - talloc_free(ares); - - if (ac->req->operation == LDB_ADD) { - /* Start the modifies to the backlinks */ - ret = la_queue_mod_request(ac); - - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, - ret); - } - } else { - /* Start with the original request */ - ret = la_down_req(ac); - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); - } - } - return LDB_SUCCESS; - } - - talloc_free(ares); - return ret; -} - - - - -/* rename */ -static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req) -{ - struct la_context *ac; - - /* This gets complex: We need to: - - Do a search for the entry - - Wait for these result to appear - - In the callback for the result, issue a modify - request based on the linked attributes found - - Wait for each modify result - - Regain our sainity - */ - - ac = linked_attributes_init(module, req); - if (!ac) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (!ac->schema) { - /* without schema, this doesn't make any sense */ - return ldb_next_request(module, req); - } - - /* start with the original request */ - return la_down_req(ac); -} - - -static int la_op_search_callback(struct ldb_request *req, - struct ldb_reply *ares) -{ - struct ldb_context *ldb; - struct la_context *ac; - const struct dsdb_attribute *schema_attr; - const struct dsdb_attribute *target_attr; - const struct ldb_message_element *el; - const char *attr_name; - int i, j; - int ret; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - /* Only entries are interesting, and we only want the olddn */ - switch (ares->type) { - case LDB_REPLY_ENTRY: - ret = ldb_dn_compare(ares->message->dn, req->op.search.base); - if (ret != 0) { - /* Guh? We only asked for this DN */ - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->message->num_elements == 0) { - /* only bother at all if there were some - * linked attributes found */ - talloc_free(ares); - return LDB_SUCCESS; + ret = dsdb_module_search_dn(module, tmp_ctx, &res, dsdb_dn->dn, + attrs, + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - remote not found - %s", + el->name, target->lDAPDisplayName, + ldb_dn_get_linearized(old_dn), + ldb_dn_get_linearized(dsdb_dn->dn), + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; } + msg = res->msgs[0]; - switch (ac->req->operation) { - case LDB_DELETE: - ac->del_dn = talloc_steal(ac, ares->message->dn); - break; - case LDB_RENAME: - ac->add_dn = talloc_steal(ac, ares->message->dn); - ac->del_dn = talloc_steal(ac, ac->req->op.rename.olddn); - break; - default: - talloc_free(ares); - ldb_set_errstring(ldb, - "operations must be delete or rename"); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); + if (msg->num_elements != 1 || + ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) { + ldb_set_errstring(ldb, "Bad msg elements in linked_attributes_fix_links"); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; } + el2 = &msg->elements[0]; - for (i = 0; i < ares->message->num_elements; i++) { - el = &ares->message->elements[i]; + el2->flags = LDB_FLAG_MOD_REPLACE; - schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name); - if (!schema_attr) { - ldb_asprintf_errstring(ldb, - "attribute %s is not a valid attribute" - " in schema", el->name); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OBJECT_CLASS_VIOLATION); + /* find our DN in the values */ + for (j=0; jnum_values; j++) { + struct dsdb_dn *dsdb_dn2; + dsdb_dn2 = dsdb_dn_parse(msg, ldb, &el2->values[j], target->syntax->ldap_oid); + if (dsdb_dn2 == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_INVALID_DN_SYNTAX; } - - /* Valid attribute, now find out if it is linked */ - if (schema_attr->linkID == 0) { - /* Not a linked attribute, skip */ + if (ldb_dn_compare(old_dn, dsdb_dn2->dn) != 0) { continue; } - - if ((schema_attr->linkID & 1) == 0) { - /* Odd is for the target. */ - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1); - if (!target_attr) { - continue; - } - attr_name = target_attr->lDAPDisplayName; - } else { - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID - 1); - if (!target_attr) { - continue; - } - attr_name = target_attr->lDAPDisplayName; - } - for (j = 0; j < el->num_values; j++) { - ret = la_store_op(ac, LA_OP_DEL, - &el->values[j], - attr_name); - - /* for renames, ensure we add it back */ - if (ret == LDB_SUCCESS - && ac->req->operation == LDB_RENAME) { - ret = la_store_op(ac, LA_OP_ADD, - &el->values[j], - attr_name); - } - if (ret != LDB_SUCCESS) { - talloc_free(ares); - return ldb_module_done(ac->req, - NULL, NULL, ret); - } - } - } - - break; - - case LDB_REPLY_REFERRAL: - /* ignore */ - break; - - case LDB_REPLY_DONE: - - talloc_free(ares); - - - switch (ac->req->operation) { - case LDB_DELETE: - /* start the mod requests chain */ - ret = la_down_req(ac); + ret = ldb_dn_update_components(dsdb_dn2->dn, new_dn); if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); + talloc_free(tmp_ctx); + return ret; } - return ret; - case LDB_RENAME: - /* start the mod requests chain */ - ret = la_queue_mod_request(ac); - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, - ret); - } - return ret; - - default: - talloc_free(ares); - ldb_set_errstring(ldb, - "operations must be delete or rename"); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); + el2->values[j] = data_blob_string_const( + dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1)); } - } - - talloc_free(ares); - return LDB_SUCCESS; -} - -/* queue a linked attributes modify request in the la_private - structure */ -static int la_queue_mod_request(struct la_context *ac) -{ - struct la_private *la_private = - talloc_get_type(ldb_module_get_private(ac->module), struct la_private); - - if (la_private == NULL) { - ldb_debug(ldb_module_get_ctx(ac->module), LDB_DEBUG_ERROR, __location__ ": No la_private transaction setup\n"); - return LDB_ERR_OPERATIONS_ERROR; - } - - talloc_steal(la_private, ac); - DLIST_ADD(la_private->la_list, ac); - - return ldb_module_done(ac->req, ac->op_controls, - ac->op_response, LDB_SUCCESS); -} - -/* Having done the original operation, then try to fix up all the linked attributes for modify and delete */ -static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - int ret; - struct la_context *ac; - struct ldb_context *ldb; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - if (ares->type != LDB_REPLY_DONE) { - ldb_set_errstring(ldb, - "invalid ldb_reply_type in callback"); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - - ac->op_controls = talloc_steal(ac, ares->controls); - ac->op_response = talloc_steal(ac, ares->response); - - /* If we have modfies to make, this is the time to do them for modify and delete */ - ret = la_queue_mod_request(ac); - - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); - } - talloc_free(ares); - - /* la_queue_mod_request has already sent the callbacks */ - return LDB_SUCCESS; - -} - -/* Having done the original rename try to fix up all the linked attributes */ -static int la_rename_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - int ret; - struct la_context *ac; - struct ldb_request *search_req; - const char **attrs; - WERROR werr; - struct ldb_context *ldb; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - if (ares->type != LDB_REPLY_DONE) { - ldb_set_errstring(ldb, - "invalid ldb_reply_type in callback"); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - - werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs); - if (!W_ERROR_IS_OK(werr)) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = ldb_build_search_req(&search_req, ldb, req, - ac->req->op.rename.newdn, LDB_SCOPE_BASE, - "(objectClass=*)", attrs, - NULL, - ac, la_op_search_callback, - req); - - if (ret != LDB_SUCCESS) { - return ret; - } - - talloc_steal(search_req, attrs); - - if (ret == LDB_SUCCESS) { - ret = ldb_request_add_control(search_req, - LDB_CONTROL_EXTENDED_DN_OID, - false, NULL); - } - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, - ret); - } - - ac->op_controls = talloc_steal(ac, ares->controls); - ac->op_response = talloc_steal(ac, ares->response); - - return ldb_next_request(ac->module, search_req); -} - -/* Having done the original add, then try to fix up all the linked attributes - - This is done after the add so the links can get the extended DNs correctly. - */ -static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - int ret; - struct la_context *ac; - struct ldb_context *ldb; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - if (ares->type != LDB_REPLY_DONE) { - ldb_set_errstring(ldb, - "invalid ldb_reply_type in callback"); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - - if (ac->ops) { - struct ldb_request *search_req; - static const char *attrs[] = { NULL }; - - /* The callback does all the hard work here - we need - * the objectGUID and SID of the added record */ - ret = ldb_build_search_req(&search_req, ldb, ac, - ac->req->op.add.message->dn, - LDB_SCOPE_BASE, - "(objectClass=*)", attrs, - NULL, - ac, la_mod_search_callback, - ac->req); - - if (ret == LDB_SUCCESS) { - ret = ldb_request_add_control(search_req, - LDB_CONTROL_EXTENDED_DN_OID, - false, NULL); - } + ret = dsdb_module_modify(module, msg, 0); if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, - ret); + ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s", + el->name, target->lDAPDisplayName, + ldb_dn_get_linearized(old_dn), + ldb_dn_get_linearized(dsdb_dn->dn), + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; } - - ac->op_controls = talloc_steal(ac, ares->controls); - ac->op_response = talloc_steal(ac, ares->response); - - return ldb_next_request(ac->module, search_req); - - } else { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); } -} - -/* Reconstruct the original request, but pointing at our local callback to finish things off */ -static int la_down_req(struct la_context *ac) -{ - struct ldb_request *down_req; - int ret; - struct ldb_context *ldb; - - ldb = ldb_module_get_ctx(ac->module); - switch (ac->req->operation) { - case LDB_ADD: - ret = ldb_build_add_req(&down_req, ldb, ac, - ac->req->op.add.message, - ac->req->controls, - ac, la_add_callback, - ac->req); - break; - case LDB_MODIFY: - ret = ldb_build_mod_req(&down_req, ldb, ac, - ac->req->op.mod.message, - ac->req->controls, - ac, la_mod_del_callback, - ac->req); - break; - case LDB_DELETE: - ret = ldb_build_del_req(&down_req, ldb, ac, - ac->req->op.del.dn, - ac->req->controls, - ac, la_mod_del_callback, - ac->req); - break; - case LDB_RENAME: - ret = ldb_build_rename_req(&down_req, ldb, ac, - ac->req->op.rename.olddn, - ac->req->op.rename.newdn, - ac->req->controls, - ac, la_rename_callback, - ac->req); - break; - default: - ret = LDB_ERR_OPERATIONS_ERROR; - } - if (ret != LDB_SUCCESS) { - return ret; - } - - return ldb_next_request(ac->module, down_req); + talloc_free(tmp_ctx); + return LDB_SUCCESS; } -/* - use the GUID part of an extended DN to find the target DN, in case - it has moved - */ -static int la_find_dn_target(struct ldb_module *module, struct la_context *ac, - struct GUID *guid, struct ldb_dn **dn) -{ - return dsdb_find_dn_by_guid(ldb_module_get_ctx(ac->module), ac, GUID_string(ac, guid), dn); -} -/* apply one la_context op change */ -static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op) +/* rename */ +static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req) { - struct ldb_message_element *ret_el; - struct ldb_request *mod_req; - struct ldb_message *new_msg; - struct ldb_context *ldb; - int ret; - - ldb = ldb_module_get_ctx(ac->module); - - /* Create the modify request */ - new_msg = ldb_msg_new(ac); - if (!new_msg) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn); - if (ret != LDB_SUCCESS) { - return ret; - } - - if (op->op == LA_OP_ADD) { - ret = ldb_msg_add_empty(new_msg, op->name, - LDB_FLAG_MOD_ADD, &ret_el); - } else { - ret = ldb_msg_add_empty(new_msg, op->name, - LDB_FLAG_MOD_DELETE, &ret_el); - } - if (ret != LDB_SUCCESS) { - return ret; - } - ret_el->values = talloc_array(new_msg, struct ldb_val, 1); - if (!ret_el->values) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - ret_el->num_values = 1; - if (op->op == LA_OP_ADD) { - ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->add_dn, 1)); - } else { - ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->del_dn, 1)); - } - -#if 0 - ldb_debug(ldb, LDB_DEBUG_WARNING, - "link on %s %s: %s %s\n", - ldb_dn_get_linearized(new_msg->dn), ret_el->name, - ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted"); -#endif - - ret = ldb_build_mod_req(&mod_req, ldb, op, - new_msg, - NULL, - NULL, - ldb_op_default_callback, - NULL); + struct ldb_result *res; + struct ldb_message *msg; + int ret, i; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_schema *schema = dsdb_get_schema(ldb); + /* + - load the current msg + - find any linked attributes + - if its a link then find the target object + - modify the target linked attributes with the new DN + */ + ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn, + NULL, DSDB_SEARCH_SHOW_DELETED); if (ret != LDB_SUCCESS) { return ret; } - talloc_steal(mod_req, new_msg); - - if (DEBUGLVL(4)) { - DEBUG(4,("Applying linked attribute change:\n%s\n", - ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg))); - } - - /* Run the new request */ - ret = ldb_next_request(module, mod_req); - - /* we need to wait for this to finish, as we are being called - from the synchronous end_transaction hook of this module */ - if (ret == LDB_SUCCESS) { - ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL); - } + msg = res->msgs[0]; - if (ret != LDB_SUCCESS) { - ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n", - ldb_errstring(ldb), - ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg)); - } - - return ret; -} - -/* apply one set of la_context changes */ -static int la_do_mod_request(struct ldb_module *module, struct la_context *ac) -{ - struct la_op_store *op; - - for (op = ac->ops; op; op=op->next) { - int ret = la_do_op_request(module, ac, op); - if (ret != LDB_SUCCESS) { - if (ret != LDB_ERR_NO_SUCH_OBJECT) { - return ret; - } + for (i=0; inum_elements; i++) { + struct ldb_message_element *el = &msg->elements[i]; + const struct dsdb_attribute *schema_attr + = dsdb_attribute_by_lDAPDisplayName(schema, el->name); + if (!schema_attr || schema_attr->linkID == 0) { + continue; } - } - - return LDB_SUCCESS; -} - - -/* - we hook into the transaction operations to allow us to - perform the linked attribute updates at the end of the whole - transaction. This allows a forward linked attribute to be created - before the target is created, as long as the target is created - in the same transaction - */ -static int linked_attributes_start_transaction(struct ldb_module *module) -{ - /* create our private structure for this transaction */ - struct la_private *la_private = talloc_get_type(ldb_module_get_private(module), - struct la_private); - talloc_free(la_private); - la_private = talloc(module, struct la_private); - if (la_private == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - la_private->la_list = NULL; - ldb_module_set_private(module, la_private); - return ldb_next_start_trans(module); -} - -/* - on prepare commit we loop over our queued la_context structures - and apply each of them - */ -static int linked_attributes_prepare_commit(struct ldb_module *module) -{ - struct la_private *la_private = - talloc_get_type(ldb_module_get_private(module), struct la_private); - struct la_context *ac; - - if (!la_private) { - /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */ - return ldb_next_prepare_commit(module); - } - /* walk the list backwards, to do the first entry first, as we - * added the entries with DLIST_ADD() which puts them at the - * start of the list */ - for (ac = la_private->la_list; ac && ac->next; ac=ac->next) ; - - for (; ac; ac=ac->prev) { - int ret; - ac->req = NULL; - ret = la_do_mod_request(module, ac); + ret = linked_attributes_fix_links(module, msg->dn, req->op.rename.newdn, el, + schema, schema_attr); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret)); - talloc_free(la_private); - ldb_module_set_private(module, NULL); + talloc_free(res); return ret; } } - talloc_free(la_private); - ldb_module_set_private(module, NULL); + talloc_free(res); - return ldb_next_prepare_commit(module); -} - -static int linked_attributes_del_transaction(struct ldb_module *module) -{ - struct la_private *la_private = - talloc_get_type(ldb_module_get_private(module), struct la_private); - talloc_free(la_private); - ldb_module_set_private(module, NULL); - return ldb_next_del_trans(module); + return ldb_next_request(module, req); } _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = { .name = "linked_attributes", - .start_transaction = linked_attributes_start_transaction, - .prepare_commit = linked_attributes_prepare_commit, - .del_transaction = linked_attributes_del_transaction, + .rename = linked_attributes_rename, }; -- cgit From e4a6f5c8b8de0429578cd09913f1d41d0a1fd82f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 23:50:41 +1100 Subject: s4-dsdb: handle links with no backlinks in replmd_delete --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 689b24f398..e184181f01 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2038,10 +2038,9 @@ static int replmd_delete_remove_link(struct ldb_module *module, msg->dn = dsdb_dn->dn; - if (sa->linkID & 1) { - target_attr = dsdb_attribute_by_linkID(schema, sa->linkID - 1); - } else { - target_attr = dsdb_attribute_by_linkID(schema, sa->linkID + 1); + target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1); + if (target_attr == NULL) { + continue; } ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2); -- cgit From f1b6484232cbcd31056b8f905f3b111d0c9069b0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 12:47:31 +1100 Subject: s4-dsdb: split RMD_USN into RMD_LOCAL_USN and RMD_ORIGINATING_USN We need a separate RMD_LOCAL_USN to allow us to tell what attributes need to be sent in a getncchanges request. Thanks to Metze for pointing this out. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 22 ++++++++++++++-------- source4/lib/ldb-samba/ldif_handlers.c | 7 ++++++- 2 files changed, 20 insertions(+), 9 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index e184181f01..822ed8868d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1172,12 +1172,13 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, /* build a new extended DN, including all meta data fields - DELETED = 1 or missing - RMD_ADDTIME = originating_add_time - RMD_INVOCID = originating_invocation_id - RMD_CHANGETIME = originating_change_time - RMD_USN = originating_usn - RMD_VERSION = version + DELETED = 1 or missing + RMD_ADDTIME = originating_add_time + RMD_INVOCID = originating_invocation_id + RMD_CHANGETIME = originating_change_time + RMD_ORIGINATING_USN = originating_usn + RMD_LOCAL_USN = local_usn + RMD_VERSION = version */ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, time_t t) @@ -1221,7 +1222,9 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval); if (ret != LDB_SUCCESS) return ret; - ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv); + ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &usnv); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv); if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); if (ret != LDB_SUCCESS) return ret; @@ -1303,7 +1306,10 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d if (ret != LDB_SUCCESS) return ret; /* update the USN */ - ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv); + ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv); + if (ret != LDB_SUCCESS) return ret; + + ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &usnv); if (ret != LDB_SUCCESS) return ret; /* increase the version by 1 */ diff --git a/source4/lib/ldb-samba/ldif_handlers.c b/source4/lib/ldb-samba/ldif_handlers.c index 5f709e6320..39fc93af95 100644 --- a/source4/lib/ldb-samba/ldif_handlers.c +++ b/source4/lib/ldb-samba/ldif_handlers.c @@ -861,7 +861,12 @@ static const struct ldb_dn_extended_syntax samba_dn_syntax[] = { .write_clear_fn = ldb_handler_copy, .write_hex_fn = ldb_handler_copy },{ - .name = "RMD_USN", + .name = "RMD_LOCAL_USN", + .read_fn = ldb_handler_copy, + .write_clear_fn = ldb_handler_copy, + .write_hex_fn = ldb_handler_copy + },{ + .name = "RMD_ORIGINATING_USN", .read_fn = ldb_handler_copy, .write_clear_fn = ldb_handler_copy, .write_hex_fn = ldb_handler_copy -- cgit From b1db66a501e3b5e5df66e722ad849a821c667d5b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:51:37 +1100 Subject: s4-dsdb: allow the component name to be specified in dsdb_get_extended_dn_guid() Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/common/util.c | 4 ++-- source4/dsdb/schema/schema_syntax.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 561edff94c..528c68b856 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2797,11 +2797,11 @@ int dsdb_functional_level(struct ldb_context *ldb) /* return a GUID from a extended DN structure */ -NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid) +NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name) { const struct ldb_val *v; - v = ldb_dn_get_extended_component(dn, "GUID"); + v = ldb_dn_get_extended_component(dn, component_name); if (v == NULL) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index 1989db0699..e958605707 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -1183,7 +1183,7 @@ static WERROR dsdb_syntax_DN_ldb_to_drsuapi(struct ldb_context *ldb, ZERO_STRUCT(id3); - status = dsdb_get_extended_dn_guid(dn, &id3.guid); + status = dsdb_get_extended_dn_guid(dn, &id3.guid, "GUID"); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { talloc_free(tmp_ctx); @@ -1367,7 +1367,7 @@ static WERROR dsdb_syntax_DN_BINARY_ldb_to_drsuapi(struct ldb_context *ldb, ZERO_STRUCT(id3); - status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &id3.guid); + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &id3.guid, "GUID"); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { talloc_free(tmp_ctx); -- cgit From 312ef9df3cdb6461e051dff4f3fe3d4ae1601392 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:56:04 +1100 Subject: s4-dsdb: add REVEAL_INTERNALS in the search for linked_attributes Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index edcb2d8167..4113a58154 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -72,7 +72,8 @@ static int linked_attributes_fix_links(struct ldb_module *module, ret = dsdb_module_search_dn(module, tmp_ctx, &res, dsdb_dn->dn, attrs, DSDB_SEARCH_SHOW_DELETED | - DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - remote not found - %s", el->name, target->lDAPDisplayName, -- cgit From 4dbcab45f263e3ccce1d10d20226d7c3c68cdc9a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:57:21 +1100 Subject: s4-dsdb: store full meta data from DRS for linked attributes Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 389 +++++++++++++++--------- 1 file changed, 239 insertions(+), 150 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 822ed8868d..95e51d1d8b 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -580,7 +580,9 @@ static void replmd_ldb_message_sort(struct ldb_message *msg, } static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, - const struct GUID *invocation_id, uint64_t seq_num, time_t t); + const struct GUID *invocation_id, uint64_t seq_num, + uint64_t local_usn, NTTIME nttime, bool deleted); + /* fix up linked attributes in replmd_add. @@ -595,6 +597,9 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme TALLOC_CTX *tmp_ctx = talloc_new(el->values); struct ldb_context *ldb = ldb_module_get_ctx(module); struct dsdb_schema *schema = dsdb_get_schema(ldb); + NTTIME now; + + unix_to_nt_time(&now, t); for (i=0; inum_values; i++) { struct ldb_val *v = &el->values[i]; @@ -603,7 +608,8 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme NTSTATUS status; int ret; - ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, seq_num, t); + ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, + seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -611,7 +617,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme /* note that the DN already has the extended components from the extended_dn_store module */ - status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid); + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID"); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; @@ -1147,7 +1153,7 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, return LDB_ERR_OPERATIONS_ERROR; } - status = dsdb_get_extended_dn_guid(dn, p->guid); + status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID"); if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { /* we got a DN without a GUID - go find the GUID */ int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid); @@ -1181,21 +1187,20 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, RMD_VERSION = version */ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, - const struct GUID *invocation_id, uint64_t seq_num, time_t t) + const struct GUID *invocation_id, uint64_t seq_num, + uint64_t local_usn, NTTIME nttime, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; - NTTIME now; const char *tstring, *usn_string; struct ldb_val tval; struct ldb_val iid; - struct ldb_val usnv; + struct ldb_val usnv, local_usnv; struct ldb_val vers; NTSTATUS status; int ret; const char *dnstring; - unix_to_nt_time(&now, t); - tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now); + tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1207,6 +1212,12 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds } usnv = data_blob_string_const(usn_string); + usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn); + if (!usn_string) { + return LDB_ERR_OPERATIONS_ERROR; + } + local_usnv = data_blob_string_const(usn_string); + vers = data_blob_string_const("0"); status = GUID_to_ndr_blob(invocation_id, dn, &iid); @@ -1214,7 +1225,13 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds return LDB_ERR_OPERATIONS_ERROR; } - ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + if (deleted) { + struct ldb_val dv; + dv = data_blob_string_const("1"); + ret = ldb_dn_set_extended_component(dn, "DELETED", &dv); + } else { + ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + } if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval); if (ret != LDB_SUCCESS) return ret; @@ -1222,7 +1239,7 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval); if (ret != LDB_SUCCESS) return ret; - ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &usnv); + ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv); if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv); if (ret != LDB_SUCCESS) return ret; @@ -1246,22 +1263,20 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds */ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, - uint64_t seq_num, time_t t, bool deleted) + uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; - NTTIME now; const char *tstring, *usn_string; struct ldb_val tval; struct ldb_val iid; - struct ldb_val usnv; + struct ldb_val usnv, local_usnv; struct ldb_val vers; const struct ldb_val *old_addtime, *old_version; NTSTATUS status; int ret; const char *dnstring; - unix_to_nt_time(&now, t); - tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now); + tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1273,6 +1288,12 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d } usnv = data_blob_string_const(usn_string); + usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn); + if (!usn_string) { + return LDB_ERR_OPERATIONS_ERROR; + } + local_usnv = data_blob_string_const(usn_string); + status = GUID_to_ndr_blob(invocation_id, dn, &iid); if (!NT_STATUS_IS_OK(status)) { return LDB_ERR_OPERATIONS_ERROR; @@ -1309,7 +1330,7 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv); if (ret != LDB_SUCCESS) return ret; - ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &usnv); + ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv); if (ret != LDB_SUCCESS) return ret; /* increase the version by 1 */ @@ -1360,6 +1381,9 @@ static int replmd_modify_la_add(struct ldb_module *module, unsigned old_num_values = old_el?old_el->num_values:0; const struct GUID *invocation_id; struct ldb_context *ldb = ldb_module_get_ctx(module); + NTTIME now; + + unix_to_nt_time(&now, t); ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid); if (ret != LDB_SUCCESS) { @@ -1390,7 +1414,7 @@ static int replmd_modify_la_add(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, - invocation_id, seq_num, t); + invocation_id, seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1408,7 +1432,7 @@ static int replmd_modify_la_add(struct ldb_module *module, return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; } ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn, - invocation_id, seq_num, t, false); + invocation_id, seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1466,6 +1490,9 @@ static int replmd_modify_la_delete(struct ldb_module *module, int ret; const struct GUID *invocation_id; struct ldb_context *ldb = ldb_module_get_ctx(module); + NTTIME now; + + unix_to_nt_time(&now, t); /* check if there is nothing to delete */ if ((!old_el || old_el->num_values == 0) && @@ -1532,7 +1559,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, if (v != NULL) continue; ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn, - invocation_id, seq_num, t, true); + invocation_id, seq_num, seq_num, now, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1579,6 +1606,9 @@ static int replmd_modify_la_replace(struct ldb_module *module, struct ldb_val *new_values = NULL; uint32_t num_new_values = 0; unsigned old_num_values = old_el?old_el->num_values:0; + NTTIME now; + + unix_to_nt_time(&now, t); /* check if there is nothing to replace */ if ((!old_el || old_el->num_values == 0) && @@ -1625,7 +1655,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, } ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, - invocation_id, seq_num, t, true); + invocation_id, seq_num, seq_num, now, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1644,7 +1674,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, /* update in place */ ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, invocation_id, - seq_num, t, false); + seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1659,7 +1689,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, - invocation_id, seq_num, t); + invocation_id, seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2027,7 +2057,7 @@ static int replmd_delete_remove_link(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } - status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2); + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID"); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; @@ -2188,7 +2218,8 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) /* we need the storage form of the parent GUID */ ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res, ldb_dn_get_parent(tmp_ctx, old_dn), NULL, - DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2398,25 +2429,38 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) return ldb_next_request(ar->module, change_req); } -static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1, - struct replPropertyMetaData1 *m2) +/* + return true if an update is newer than an existing entry + see section 5.11 of MS-ADTS +*/ +static bool replmd_update_is_newer(const struct GUID *current_invocation_id, + const struct GUID *update_invocation_id, + uint32_t current_version, + uint32_t update_version, + NTTIME current_change_time, + NTTIME update_change_time) { - int ret; - - if (m1->version != m2->version) { - return m1->version - m2->version; + if (update_version != current_version) { + return update_version > current_version; } - - if (m1->originating_change_time != m2->originating_change_time) { - return m1->originating_change_time - m2->originating_change_time; + if (update_change_time > current_change_time) { + return true; } - - ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id); - if (ret != 0) { - return ret; + if (update_change_time == current_change_time) { + return GUID_compare(update_invocation_id, current_invocation_id) > 0; } + return false; +} - return m1->originating_usn - m2->originating_usn; +static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m, + struct replPropertyMetaData1 *new_m) +{ + return replmd_update_is_newer(&cur_m->originating_invocation_id, + &new_m->originating_invocation_id, + cur_m->version, + new_m->version, + cur_m->originating_change_time, + new_m->originating_change_time); } static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) @@ -2494,21 +2538,26 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) bool found = false; for (j=0; j < ni; j++) { - int cmp; + bool cmp; if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) { continue; } - cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i], - &nmd.ctr.ctr1.array[j]); - if (cmp > 0) { + cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j], + &rmd->ctr.ctr1.array[i]); + if (cmp) { /* replace the entry */ nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i]; found = true; break; } + DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n", + msg->elements[i-removed_attrs].name, + ldb_dn_get_linearized(msg->dn), + GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id))); + /* we don't want to apply this change so remove the attribute */ ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]); removed_attrs++; @@ -3210,21 +3259,23 @@ static int replmd_process_linked_attribute(struct ldb_module *module, struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la; struct ldb_context *ldb = ldb_module_get_ctx(module); struct dsdb_schema *schema = dsdb_get_schema(ldb); - struct drsuapi_DsReplicaObjectIdentifier3 target; struct ldb_message *msg; TALLOC_CTX *tmp_ctx = talloc_new(la_entry); - struct ldb_request *mod_req; int ret; const struct dsdb_attribute *attr; - struct ldb_dn *target_dn; struct dsdb_dn *dsdb_dn; uint64_t seq_num = 0; struct drsuapi_DsReplicaAttribute drs; struct drsuapi_DsAttributeValue val; - struct ldb_message_element el; - const struct ldb_val *guid; + struct ldb_message_element new_el, *old_el; WERROR status; time_t t = time(NULL); + struct ldb_result *res; + const char *attrs[2]; + struct parsed_dn *pdn_list, *pdn; + struct GUID guid; + NTSTATUS ntstatus; + bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false; drs.value_ctr.num_values = 1; drs.value_ctr.values = &val; @@ -3273,153 +3324,191 @@ linked_attributes[0]: return LDB_ERR_OPERATIONS_ERROR; } - status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &el); - - /* construct a modify request for this attribute change */ - msg = ldb_msg_new(tmp_ctx); - if (!msg) { - ldb_oom(ldb); - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } + attrs[0] = attr->lDAPDisplayName; + attrs[1] = NULL; - ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, - GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn); + /* get the existing message from the db for the object with + this GUID, returning attribute being modified. We will then + use this msg as the basis for a modify call */ + ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs, + DSDB_SEARCH_SEARCH_ALL_PARTITIONS | + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS, + "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid)); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } + if (res->count != 1) { + ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found", + GUID_string(tmp_ctx, &la->identifier->guid)); + talloc_free(tmp_ctx); + return LDB_ERR_NO_SUCH_OBJECT; + } + msg = res->msgs[0]; - el.name = attr->lDAPDisplayName; - if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) { - ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_ADD); + if (msg->num_elements == 0) { + ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el); + if (ret != LDB_SUCCESS) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } } else { - ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_DELETE); + old_el = &msg->elements[0]; + old_el->flags = LDB_FLAG_MOD_REPLACE; } + + /* parse the existing links */ + ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } - dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el.values[0], attr->syntax->ldap_oid); - if (!dsdb_dn) { - DEBUG(0,(__location__ ": Failed to parse just-generated DN\n")); - talloc_free(tmp_ctx); - return LDB_ERR_INVALID_DN_SYNTAX; + status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el); + if (!W_ERROR_IS_OK(status)) { + ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn)); + return LDB_ERR_OPERATIONS_ERROR; } - guid = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID"); - if (!guid) { - DEBUG(0,(__location__ ": Failed to parse GUID from just-generated DN\n")); - talloc_free(tmp_ctx); - return LDB_ERR_INVALID_DN_SYNTAX; + if (new_el.num_values != 1) { + ldb_asprintf_errstring(ldb, "Failed to find value in linked attribute blob for %s on %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn)); + return LDB_ERR_OPERATIONS_ERROR; } - ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, ldb_binary_encode(tmp_ctx, *guid), &target_dn); - if (ret != LDB_SUCCESS) { - /* If this proves to be a problem in the future, then - * just remove the return - perhaps we can just use - * the details the replication peer supplied */ - - DEBUG(0,(__location__ ": Failed to map GUID %s to DN\n", GUID_string(tmp_ctx, &target.guid))); - talloc_free(tmp_ctx); + dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &new_el.values[0], attr->syntax->ldap_oid); + if (!dsdb_dn) { + ldb_asprintf_errstring(ldb, "Failed to parse DN in linked attribute blob for %s on %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_OPERATIONS_ERROR; - } else { - - /* Now update with full DN we just found in the DB (including extended components) */ - dsdb_dn->dn = target_dn; - /* Now make a linearized version, using the original binary components (if any) */ - el.values[0] = data_blob_string_const(dsdb_dn_get_extended_linearized(tmp_ctx, dsdb_dn, 1)); } - ret = replmd_update_rpmd(module, schema, msg, &seq_num, t); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; + ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID"); + if (!NT_STATUS_IS_OK(ntstatus)) { + ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn)); + return LDB_ERR_OPERATIONS_ERROR; } - /* we only change whenChanged and uSNChanged if the seq_num - has changed */ - if (seq_num != 0) { - if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { + /* see if this link already exists */ + pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid); + if (pdn != NULL) { + /* see if this update is newer than what we have already */ + struct GUID invocation_id = GUID_zero(); + uint32_t version = 0; + NTTIME change_time = 0; + bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL; + + dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID"); + dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION"); + dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME"); + + if (!replmd_update_is_newer(&invocation_id, + &la->meta_data.originating_invocation_id, + version, + la->meta_data.version, + change_time, + la->meta_data.originating_change_time)) { + DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn), + GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id))); talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; + return LDB_SUCCESS; } - if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) { + /* get a seq_num for this change */ + ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num); + if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; + return ret; } - } - - ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx, - msg, - NULL, - NULL, - ldb_op_default_callback, - NULL); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; - } - talloc_steal(mod_req, msg); - if (DEBUGLVL(4)) { - DEBUG(4,("Applying DRS linked attribute change:\n%s\n", - ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg))); - } - - /* Run the new request */ - ret = ldb_next_request(module, mod_req); + if (was_active) { + /* remove the existing backlink */ + ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } - /* we need to wait for this to finish, as we are being called - from the synchronous end_transaction hook of this module */ - if (ret == LDB_SUCCESS) { - ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL); - } + ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn, + &la->meta_data.originating_invocation_id, + la->meta_data.originating_usn, seq_num, + la->meta_data.originating_change_time, + !active); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } - if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) { - /* the link destination exists, we need to update it - * by deleting the old one for the same DN then adding - * the new one */ - msg->elements = talloc_realloc(msg, msg->elements, - struct ldb_message_element, - msg->num_elements+1); - if (msg->elements == NULL) { - ldb_oom(ldb); + if (active) { + /* add the new backlink */ + ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + } else { + /* get a seq_num for this change */ + ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num); + if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); + return ret; + } + + old_el->values = talloc_realloc(msg->elements, old_el->values, + struct ldb_val, old_el->num_values+1); + if (!old_el->values) { + ldb_module_oom(module); return LDB_ERR_OPERATIONS_ERROR; } - /* this relies on the backend matching the old entry - only by the DN portion of the extended DN */ - msg->elements[1] = msg->elements[0]; - msg->elements[0].flags = LDB_FLAG_MOD_DELETE; - msg->num_elements++; - - ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx, - msg, - NULL, - NULL, - ldb_op_default_callback, - NULL); + old_el->num_values++; + + ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn, + &la->meta_data.originating_invocation_id, + la->meta_data.originating_usn, seq_num, + la->meta_data.originating_change_time, + (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } - /* Run the new request */ - ret = ldb_next_request(module, mod_req); - - if (ret == LDB_SUCCESS) { - ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL); + if (active) { + ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, + true, attr, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } } + /* we only change whenChanged and uSNChanged if the seq_num + has changed */ + if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = dsdb_module_modify(module, msg, 0); if (ret != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n", ldb_errstring(ldb), ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)); - ret = LDB_SUCCESS; + talloc_free(tmp_ctx); + return ret; } talloc_free(tmp_ctx); -- cgit From 809bcfca3d835458010013c0454b16d7f2a9fdf3 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 12:23:22 +1100 Subject: s4-dsdb: minor cleanup in DRS replicated objects code --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 95e51d1d8b..3e6455c089 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2378,14 +2378,15 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) /* remove any message elements that have zero values */ for (i=0; inum_elements; i++) { - if (msg->elements[i].num_values == 0) { + struct ldb_message_element *el = &msg->elements[i]; + + if (el->num_values == 0) { DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n", - msg->elements[i].name)); - memmove(&msg->elements[i], - &msg->elements[i+1], - sizeof(msg->elements[i])*(msg->num_elements - (i+1))); + el->name)); + memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1))); msg->num_elements--; i--; + continue; } } -- cgit From beba977213daf5ff4004954e03481e970d1749cb Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 12:24:09 +1100 Subject: s4-dsdb: ask for REVEAL_INTERNALS in getncchanges We need this for the linked attribute meta data --- source4/rpc_server/drsuapi/drsutil.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/drsutil.c b/source4/rpc_server/drsuapi/drsutil.c index a62f911537..43692ac5b4 100644 --- a/source4/rpc_server/drsuapi/drsutil.c +++ b/source4/rpc_server/drsuapi/drsutil.c @@ -86,6 +86,11 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb, return ret; } + ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL); + if (ret != LDB_SUCCESS) { + return ret; + } + if (sort_attrib) { struct ldb_server_sort_control **sort_control; sort_control = talloc_array(req, struct ldb_server_sort_control *, 2); -- cgit From fde3f6437369365af7bb72bcff1666bf0ce98948 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 12:25:09 +1100 Subject: s4-drs: added linked attribute replication to getncchanges --- source4/rpc_server/drsuapi/getncchanges.c | 218 ++++++++++++++++++++++++++++-- 1 file changed, 203 insertions(+), 15 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 488ecd129e..e07aca6e65 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -30,6 +30,32 @@ #include "../libcli/drsuapi/drsuapi.h" #include "libcli/security/security.h" +/* + build a DsReplicaObjectIdentifier from a ldb msg + */ +static struct drsuapi_DsReplicaObjectIdentifier *get_object_identifier(TALLOC_CTX *mem_ctx, + struct ldb_message *msg) +{ + struct drsuapi_DsReplicaObjectIdentifier *identifier; + struct dom_sid *sid; + + identifier = talloc(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier); + if (identifier == NULL) { + return NULL; + } + + identifier->dn = ldb_dn_alloc_linearized(identifier, msg->dn); + identifier->guid = samdb_result_guid(msg, "objectGUID"); + + sid = samdb_result_dom_sid(identifier, msg, "objectSid"); + if (sid) { + identifier->sid = *sid; + } else { + ZERO_STRUCT(identifier->sid); + } + return identifier; +} + /* drsuapi_DsGetNCChanges for one object */ @@ -44,9 +70,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem { const struct ldb_val *md_value; int i, n; - struct ldb_dn *obj_dn; struct replPropertyMetaDataBlob md; - struct dom_sid *sid; uint32_t rid = 0; enum ndr_err_code ndr_err; uint32_t *attids; @@ -104,17 +128,11 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem obj->meta_data_ctr = talloc(obj, struct drsuapi_DsReplicaMetaDataCtr); attids = talloc_array(obj, uint32_t, md.ctr.ctr1.count); - obj->object.identifier = talloc(obj, struct drsuapi_DsReplicaObjectIdentifier); - obj_dn = ldb_msg_find_attr_as_dn(sam_ctx, obj, msg, "distinguishedName"); - obj->object.identifier->dn = ldb_dn_get_linearized(obj_dn); - obj->object.identifier->guid = samdb_result_guid(msg, "objectGUID"); - sid = samdb_result_dom_sid(obj, msg, "objectSid"); - if (sid) { - dom_sid_split_rid(NULL, sid, NULL, &rid); - obj->object.identifier->sid = *sid; - } else { - ZERO_STRUCT(obj->object.identifier->sid); + obj->object.identifier = get_object_identifier(obj, msg); + if (obj->object.identifier == NULL) { + return WERR_NOMEM; } + dom_sid_split_rid(NULL, &obj->object.identifier->sid, NULL, &rid); obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count); for (n=i=0; iidentifier = get_object_identifier(*la_list, msg); + W_ERROR_HAVE_NO_MEMORY(la->identifier); + + active = ldb_dn_get_extended_component(dsdb_dn->dn, "DELETED")?false:true; + + la->attid = sa->attributeID_id; + la->flags = active?DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:0; + + status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->originating_add_time, "RMD_ADDTIME"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + status = dsdb_get_extended_dn_uint32(dsdb_dn->dn, &la->meta_data.version, "RMD_VERSION"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->meta_data.originating_change_time, "RMD_CHANGETIME"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &la->meta_data.originating_invocation_id, "RMD_INVOCID"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &la->meta_data.originating_usn, "RMD_ORIGINATING_USN"); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + /* we need a message_element with just one value in it */ + v = data_blob_string_const(dsdb_dn_get_linearized(*la_list, dsdb_dn)); + + val_el = *el; + val_el.values = &v; + val_el.num_values = 1; + + werr = sa->syntax->ldb_to_drsuapi(sam_ctx, schema, sa, &val_el, *la_list, &drs); + W_ERROR_NOT_OK_RETURN(werr); + + if (drs.value_ctr.num_values != 1) { + DEBUG(1,(__location__ ": Failed to build DRS blob for linked attribute %s in %s\n", + el->name, ldb_dn_get_linearized(msg->dn))); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + la->value.blob = drs.value_ctr.values[0].blob; + + (*la_count)++; + return WERR_OK; +} + + +/* + add linked attributes from an object to the list of linked + attributes in a getncchanges request + */ +static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx, + TALLOC_CTX *mem_ctx, + struct ldb_dn *ncRoot_dn, + struct dsdb_schema *schema, + uint64_t highest_usn, + uint32_t replica_flags, + struct ldb_message *msg, + struct drsuapi_DsReplicaLinkedAttribute **la_list, + uint32_t *la_count) +{ + int i; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + + for (i=0; inum_elements; i++) { + struct ldb_message_element *el = &msg->elements[i]; + const struct dsdb_attribute *sa; + int j; + + sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name); + + if (!sa || sa->linkID == 0 || (sa->linkID & 1)) { + /* we only want forward links */ + continue; + } + + for (j=0; jnum_values; j++) { + struct dsdb_dn *dsdb_dn; + uint64_t local_usn; + NTSTATUS status; + WERROR werr; + + dsdb_dn = dsdb_dn_parse(tmp_ctx, sam_ctx, &el->values[j], sa->syntax->ldap_oid); + if (dsdb_dn == NULL) { + DEBUG(1,(__location__ ": Failed to parse DN for %s in %s\n", + el->name, ldb_dn_get_linearized(msg->dn))); + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &local_usn, "RMD_LOCAL_USN"); + if (!NT_STATUS_IS_OK(status)) { + /* this can happen for attributes + given to us with old style meta + data */ + continue; + } + + if (local_usn < highest_usn) { + continue; + } + + werr = get_nc_changes_add_la(mem_ctx, sam_ctx, schema, sa, msg, + el, dsdb_dn, la_list, la_count); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(tmp_ctx); + return werr; + } + } + } + + talloc_free(tmp_ctx); + return WERR_OK; +} + /* load replUpToDateVector from a DN */ @@ -494,15 +660,24 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ r->out.ctr->ctr6.first_object = NULL; currentObject = &r->out.ctr->ctr6.first_object; +#if 0 + /* use this to force single objects at a time, which is useful + * for working out what object is giving problems + */ + req8->max_object_count = 1; +#endif + for(i=getnc_state->num_sent; isite_res->count && (r->out.ctr->ctr6.object_count < req8->max_object_count); i++) { int uSN; struct drsuapi_DsReplicaObjectListItemEx *obj; + struct ldb_message *msg = getnc_state->site_res->msgs[i]; + obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx); - uSN = ldb_msg_find_attr_as_int(getnc_state->site_res->msgs[i], "uSNChanged", -1); + uSN = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1); if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) { r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN; } @@ -510,7 +685,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ getnc_state->highest_usn = uSN; } - werr = get_nc_changes_build_object(obj, getnc_state->site_res->msgs[i], + werr = get_nc_changes_build_object(obj, msg, b_state->sam_ctx, getnc_state->ncRoot_dn, schema, &session_key, getnc_state->min_usn, req8->replica_flags); @@ -518,9 +693,20 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ return werr; } + werr = get_nc_changes_add_links(b_state->sam_ctx, mem_ctx, + getnc_state->ncRoot_dn, + schema, getnc_state->min_usn, + req8->replica_flags, + msg, + &r->out.ctr->ctr6.linked_attributes, + &r->out.ctr->ctr6.linked_attributes_count); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + if (obj->meta_data_ctr == NULL) { DEBUG(0,(__location__ ": getncchanges skipping send of object %s\n", - ldb_dn_get_linearized(getnc_state->site_res->msgs[i]->dn))); + ldb_dn_get_linearized(msg->dn))); /* no attributes to send */ talloc_free(obj); continue; @@ -530,6 +716,8 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ *currentObject = obj; currentObject = &obj->next_object; + + DEBUG(8,(__location__ ": replicating object %s\n", ldb_dn_get_linearized(msg->dn))); } getnc_state->num_sent += r->out.ctr->ctr6.object_count; -- cgit From 26ec526d02d78fb327fb855ce5ff037cb74af303 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 19:57:37 +1100 Subject: s4-dsdb: auto-upgrade w2k formatted linked attributes when modified When any value of a w2k formatted linked attribute is modified, upgrade the links. --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 63 +++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3e6455c089..7f797752d0 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1255,6 +1255,35 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds return LDB_SUCCESS; } +static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, + struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, + uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted); + +/* + check if any links need upgrading from w2k format + */ +static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id) +{ + int i; + for (i=0; idn, &version, "RMD_VERSION"); + if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + continue; + } + + /* it's an old one that needs upgrading */ + ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id, + 1, 1, 0, false); + if (ret != LDB_SUCCESS) { + return ret; + } + } + return LDB_SUCCESS; +} /* update an extended DN, including all meta data fields @@ -1399,9 +1428,16 @@ static int replmd_modify_la_add(struct ldb_module *module, invocation_id = samdb_ntds_invocation_id(ldb); if (!invocation_id) { + talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } + ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + /* for each new value, see if it exists already with the same GUID */ for (i=0; inum_values; i++) { struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid); @@ -1521,6 +1557,12 @@ static int replmd_modify_la_delete(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } + ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + el->values = NULL; /* see if we are being asked to delete any links that @@ -1633,6 +1675,12 @@ static int replmd_modify_la_replace(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } + ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + /* mark all the old ones as deleted */ for (i=0; iflags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false; + const struct GUID *our_invocation_id; drs.value_ctr.num_values = 1; drs.value_ctr.values = &val; @@ -3368,6 +3417,20 @@ linked_attributes[0]: return ret; } + /* get our invocationId */ + our_invocation_id = samdb_ntds_invocation_id(ldb); + if (!our_invocation_id) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n"); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el); if (!W_ERROR_IS_OK(status)) { ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n", -- cgit From b34db0840de701b4d42918a8da952959a6955453 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 20:55:11 +1100 Subject: s4-ldb: use the RELAX control to disable single value checking on replace When using w2k3 linked attributes we are allowed to have multiple values on a single valued attribute. This happens when the other values are deleted. Setting the RELAX control tell the ldb-tdb backend to not check for this on replace, which means the caller has to check for single valued violations. --- source4/lib/ldb/ldb_tdb/ldb_cache.c | 2 +- source4/lib/ldb/ldb_tdb/ldb_tdb.c | 17 ++++++++++++++--- source4/lib/ldb/ldb_tdb/ldb_tdb.h | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/ldb_tdb/ldb_cache.c b/source4/lib/ldb/ldb_tdb/ldb_cache.c index cd2249d4a2..aa19f75e9c 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_cache.c +++ b/source4/lib/ldb/ldb_tdb/ldb_cache.c @@ -463,7 +463,7 @@ int ltdb_increase_sequence_number(struct ldb_module *module) val_time.data = (uint8_t *)s; val_time.length = strlen(s); - ret = ltdb_modify_internal(module, msg); + ret = ltdb_modify_internal(module, msg, NULL); talloc_free(msg); diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c index 227a202a6f..a146b96b20 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c @@ -592,9 +592,12 @@ static int msg_delete_element(struct ldb_module *module, yuck - this is O(n^2). Luckily n is usually small so we probably get away with it, but if we ever have really large attribute lists then we'll need to look at this again + + 'req' is optional, and is used to specify controls if supplied */ int ltdb_modify_internal(struct ldb_module *module, - const struct ldb_message *msg) + const struct ldb_message *msg, + struct ldb_request *req) { struct ldb_context *ldb = ldb_module_get_ctx(module); void *data = ldb_module_get_private(module); @@ -731,7 +734,15 @@ int ltdb_modify_internal(struct ldb_module *module, case LDB_FLAG_MOD_REPLACE: if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) { - if (el->num_values > 1) { + /* the RELAX control overrides this + check for replace. This is needed as + DRS replication can produce multiple + values here for a single valued + attribute when the values are deleted + links + */ + if (el->num_values > 1 && + (!req || !ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))) { ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once", el->name, ldb_dn_get_linearized(msg2->dn)); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; @@ -852,7 +863,7 @@ static int ltdb_modify(struct ltdb_context *ctx) return LDB_ERR_OPERATIONS_ERROR; } - ret = ltdb_modify_internal(module, req->op.mod.message); + ret = ltdb_modify_internal(module, req->op.mod.message, req); return ret; } diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.h b/source4/lib/ldb/ldb_tdb/ldb_tdb.h index bb4cb3f8b5..70b99c340c 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.h +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.h @@ -130,7 +130,7 @@ int ltdb_lock_read(struct ldb_module *module); int ltdb_unlock_read(struct ldb_module *module); struct TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn); int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs); -int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg); +int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg, struct ldb_request *req); int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn); int ltdb_err_map(enum TDB_ERROR tdb_code); -- cgit From 64802c5e2711eec1a0046098955354e5cd978636 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 20:55:46 +1100 Subject: s4-dsdb: added dsdb_dn_is_upgraded_link_val() This is used to detect if a link has been stored in the w2k3 extended format --- source4/dsdb/common/util.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 528c68b856..ef47079f9f 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2874,6 +2874,15 @@ bool dsdb_dn_is_deleted_val(struct ldb_val *val) return false; } +/* + return true if a ldb_val containing a DN in storage form is + in the upgraded w2k3 linked attribute format + */ +bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val) +{ + return memmem(val->data, val->length, " Date: Sat, 19 Dec 2009 20:59:04 +1100 Subject: s4-drs: handle mixtures of old and new style links in getncchanges We need to send non-upgraded links using the old format --- source4/rpc_server/drsuapi/getncchanges.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index e07aca6e65..b3808206cb 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -136,6 +136,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count); for (n=i=0; iattributeID_id) continue; + sa = dsdb_attribute_by_attributeID_id(schema, md.ctr.ctr1.array[i].attid); + if (sa->linkID) { + struct ldb_message_element *el; + el = ldb_msg_find_element(msg, sa->lDAPDisplayName); + if (el && el->num_values && dsdb_dn_is_upgraded_link_val(&el->values[0])) { + /* don't send upgraded links inline */ + continue; + } + } + obj->meta_data_ctr->meta_data[n].originating_change_time = md.ctr.ctr1.array[i].originating_change_time; obj->meta_data_ctr->meta_data[n].version = md.ctr.ctr1.array[i].version; obj->meta_data_ctr->meta_data[n].originating_invocation_id = md.ctr.ctr1.array[i].originating_invocation_id; @@ -326,6 +337,12 @@ static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx, continue; } + if (el->num_values && !dsdb_dn_is_upgraded_link_val(&el->values[0])) { + /* its an old style link, it will have been + * sent in the main replication data */ + continue; + } + for (j=0; jnum_values; j++) { struct dsdb_dn *dsdb_dn; uint64_t local_usn; -- cgit From 3c1259f10eb827de05198a8eaf79a4610d1d41e6 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 21:40:55 +1100 Subject: s4-dsdb: added dsdb_check_single_valued_link() This is used in conjunction with the RELAX control, to check for violations of single value rules for linked attributes --- source4/dsdb/samdb/ldb_modules/util.c | 29 +++++++++++++++++++++++++++++ source4/dsdb/samdb/ldb_modules/util.h | 2 ++ 2 files changed, 31 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index b0ccd0341c..fa451f4bcf 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -371,3 +371,32 @@ const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *sc return last_class; } + +/* + check if a single valued link has multiple non-deleted values + + This is needed when we will be using the RELAX control to stop + ldb_tdb from checking single valued links + */ +int dsdb_check_single_valued_link(const struct dsdb_attribute *attr, + const struct ldb_message_element *el) +{ + bool found_active = false; + int i; + + if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) || + el->num_values < 2) { + return LDB_SUCCESS; + } + + for (i=0; inum_values; i++) { + if (!dsdb_dn_is_deleted_val(&el->values[i])) { + if (found_active) { + return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; + } + found_active = true; + } + } + + return LDB_SUCCESS; +} diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h index cc184eee8f..66579ab852 100644 --- a/source4/dsdb/samdb/ldb_modules/util.h +++ b/source4/dsdb/samdb/ldb_modules/util.h @@ -21,6 +21,8 @@ struct dsdb_schema; /* predeclare schema struct */ struct GUID; +struct dsdb_attribute; + #include "dsdb/samdb/ldb_modules/util_proto.h" #define DSDB_SEARCH_SEARCH_ALL_PARTITIONS 0x0001 -- cgit From 5dcb903f26045656372993822debcfbc956827b0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 21:42:40 +1100 Subject: s4-dsdb: move checking for single valued links to samba modules This uses the RELAX control and checking of single valued attributes in ldb modules to avoid problems with multi-valued links where all values but one are deleted --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 8 +++++++- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 4113a58154..4c326bc240 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -116,7 +116,13 @@ static int linked_attributes_fix_links(struct ldb_module *module, dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1)); } - ret = dsdb_module_modify(module, msg, 0); + ret = dsdb_check_single_valued_link(target, el2); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s", el->name, target->lDAPDisplayName, diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 7f797752d0..d3a7e3791c 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3566,9 +3566,15 @@ linked_attributes[0]: return LDB_ERR_OPERATIONS_ERROR; } - ret = dsdb_module_modify(module, msg, 0); + ret = dsdb_check_single_valued_link(attr, old_el); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX); if (ret != LDB_SUCCESS) { - ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n", + ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n", ldb_errstring(ldb), ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)); talloc_free(tmp_ctx); -- cgit From bf8ccd21f1f421f8d76f4882f2c3df8d429413b7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 00:10:40 +1100 Subject: s4-dsdb: fill in the correct version number of links that come over DRS --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 53 +++++++++++++------------ 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index d3a7e3791c..bf4a55054a 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -581,7 +581,7 @@ static void replmd_ldb_message_sort(struct ldb_message *msg, static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, - uint64_t local_usn, NTTIME nttime, bool deleted); + uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted); /* @@ -609,7 +609,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme int ret; ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, - seq_num, seq_num, now, false); + seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1188,7 +1188,7 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, */ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, - uint64_t local_usn, NTTIME nttime, bool deleted) + uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; const char *tstring, *usn_string; @@ -1199,6 +1199,7 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds NTSTATUS status; int ret; const char *dnstring; + char *vstring; tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { @@ -1218,7 +1219,8 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds } local_usnv = data_blob_string_const(usn_string); - vers = data_blob_string_const("0"); + vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version); + vers = data_blob_string_const(vstring); status = GUID_to_ndr_blob(invocation_id, dn, &iid); if (!NT_STATUS_IS_OK(status)) { @@ -1257,7 +1259,8 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, - uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted); + uint64_t seq_num, uint64_t local_usn, NTTIME nttime, + uint32_t version, bool deleted); /* check if any links need upgrading from w2k format @@ -1277,7 +1280,7 @@ static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, con /* it's an old one that needs upgrading */ ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id, - 1, 1, 0, false); + 1, 1, 0, 0, false); if (ret != LDB_SUCCESS) { return ret; } @@ -1292,7 +1295,8 @@ static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, con */ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, - uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted) + uint64_t seq_num, uint64_t local_usn, NTTIME nttime, + uint32_t version, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; const char *tstring, *usn_string; @@ -1300,10 +1304,12 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d struct ldb_val iid; struct ldb_val usnv, local_usnv; struct ldb_val vers; - const struct ldb_val *old_addtime, *old_version; + const struct ldb_val *old_addtime; + uint32_t old_version; NTSTATUS status; int ret; const char *dnstring; + char *vstring; tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { @@ -1363,19 +1369,12 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d if (ret != LDB_SUCCESS) return ret; /* increase the version by 1 */ - old_version = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_VERSION"); - if (old_version == NULL) { - vers = data_blob_string_const("0"); - } else { - char *vstring; - vstring = talloc_strndup(dn, (const char *)old_version->data, old_version->length); - if (!vstring) { - return LDB_ERR_OPERATIONS_ERROR; - } - vstring = talloc_asprintf(dn, "%lu", - (unsigned long)strtoul(vstring, NULL, 0)+1); - vers = data_blob_string_const(vstring); + status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION"); + if (NT_STATUS_IS_OK(status) && old_version >= version) { + version = old_version+1; } + vstring = talloc_asprintf(dn, "%lu", (unsigned long)version); + vers = data_blob_string_const(vstring); ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); if (ret != LDB_SUCCESS) return ret; @@ -1450,7 +1449,7 @@ static int replmd_modify_la_add(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, - invocation_id, seq_num, seq_num, now, false); + invocation_id, seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1468,7 +1467,7 @@ static int replmd_modify_la_add(struct ldb_module *module, return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; } ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn, - invocation_id, seq_num, seq_num, now, false); + invocation_id, seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1601,7 +1600,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, if (v != NULL) continue; ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn, - invocation_id, seq_num, seq_num, now, true); + invocation_id, seq_num, seq_num, now, 0, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1703,7 +1702,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, } ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, - invocation_id, seq_num, seq_num, now, true); + invocation_id, seq_num, seq_num, now, 0, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1722,7 +1721,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, /* update in place */ ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, invocation_id, - seq_num, seq_num, now, false); + seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1737,7 +1736,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, - invocation_id, seq_num, seq_num, now, false); + invocation_id, seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -3504,6 +3503,7 @@ linked_attributes[0]: &la->meta_data.originating_invocation_id, la->meta_data.originating_usn, seq_num, la->meta_data.originating_change_time, + la->meta_data.version, !active); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -3538,6 +3538,7 @@ linked_attributes[0]: &la->meta_data.originating_invocation_id, la->meta_data.originating_usn, seq_num, la->meta_data.originating_change_time, + la->meta_data.version, (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); -- cgit From bcc952d19dd5e1731386ccd1d7150e4bc306c60c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 00:12:35 +1100 Subject: s4-drs: some useful debugging options for getncchanges Added two debugging parametric options drs:max object sync = drs:extra filter = --- source4/rpc_server/drsuapi/getncchanges.c | 53 ++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 11 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index b3808206cb..84dc21d1b7 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -25,6 +25,7 @@ #include "dsdb/samdb/samdb.h" #include "param/param.h" #include "librpc/gen_ndr/ndr_drsblobs.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" #include "rpc_server/drsuapi/dcesrv_drsuapi.h" #include "rpc_server/dcerpc_server_proto.h" #include "../libcli/drsuapi/drsuapi.h" @@ -324,6 +325,7 @@ static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx, { int i; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + uint64_t uSNChanged = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1); for (i=0; inum_elements; i++) { struct ldb_message_element *el = &msg->elements[i]; @@ -365,6 +367,13 @@ static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx, continue; } + if (local_usn > uSNChanged) { + DEBUG(1,(__location__ ": uSNChanged less than RMD_LOCAL_USN for %s on %s\n", + el->name, ldb_dn_get_linearized(msg->dn))); + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + if (local_usn < highest_usn) { continue; } @@ -472,6 +481,7 @@ struct drsuapi_getncchanges_state { struct ldb_dn *ncRoot_dn; uint64_t min_usn; uint64_t highest_usn; + struct ldb_dn *last_dn; }; /* @@ -506,6 +516,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ struct drsuapi_getncchanges_state *getnc_state; struct drsuapi_DsGetNCChangesRequest8 *req8; uint32_t options; + uint32_t max_objects; DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; @@ -572,9 +583,10 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ if (getnc_state) { struct ldb_dn *new_dn = ldb_dn_new(getnc_state, b_state->sam_ctx, ncRoot->dn); if (ldb_dn_compare(new_dn, getnc_state->ncRoot_dn) != 0) { - DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s\n", + DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s (last_dn %s)\n", ldb_dn_get_linearized(new_dn), - ldb_dn_get_linearized(getnc_state->ncRoot_dn))); + ldb_dn_get_linearized(getnc_state->ncRoot_dn), + ldb_dn_get_linearized(getnc_state->last_dn))); talloc_free(getnc_state); getnc_state = NULL; } @@ -616,6 +628,9 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ if (getnc_state->site_res == NULL) { char* search_filter; enum ldb_scope scope = LDB_SCOPE_SUBTREE; + const char *extra_filter; + + extra_filter = lp_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter"); getnc_state->min_usn = req8->highwatermark.highest_usn; @@ -624,6 +639,10 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ "(uSNChanged>=%llu)", (unsigned long long)(getnc_state->min_usn+1)); + if (extra_filter) { + search_filter = talloc_asprintf(mem_ctx, "(&%s(%s))", search_filter, extra_filter); + } + if (req8->replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_CRITICAL_ONLY) { search_filter = talloc_asprintf(mem_ctx, "(&%s(isCriticalSystemObject=TRUE))", @@ -677,16 +696,17 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ r->out.ctr->ctr6.first_object = NULL; currentObject = &r->out.ctr->ctr6.first_object; -#if 0 /* use this to force single objects at a time, which is useful * for working out what object is giving problems */ - req8->max_object_count = 1; -#endif + max_objects = lp_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "max object sync", 1000); + if (req8->max_object_count < max_objects) { + max_objects = req8->max_object_count; + } for(i=getnc_state->num_sent; isite_res->count && - (r->out.ctr->ctr6.object_count < req8->max_object_count); + (r->out.ctr->ctr6.object_count < max_objects); i++) { int uSN; struct drsuapi_DsReplicaObjectListItemEx *obj; @@ -734,6 +754,9 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ *currentObject = obj; currentObject = &obj->next_object; + talloc_free(getnc_state->last_dn); + getnc_state->last_dn = ldb_dn_copy(getnc_state, msg->dn); + DEBUG(8,(__location__ ": replicating object %s\n", ldb_dn_get_linearized(msg->dn))); } @@ -785,11 +808,19 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ b_state->getncchanges_state = NULL; } - DEBUG(2,("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %d/%d)\n", - (unsigned long long)(req8->highwatermark.highest_usn+1), - req8->replica_flags, - ncRoot->dn, r->out.ctr->ctr6.object_count, - i, r->out.ctr->ctr6.more_data?getnc_state->site_res->count:i)); + DEBUG(r->out.ctr->ctr6.more_data?2:1, + ("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %d/%d la=%d)\n", + (unsigned long long)(req8->highwatermark.highest_usn+1), + req8->replica_flags, + ncRoot->dn, r->out.ctr->ctr6.object_count, + i, r->out.ctr->ctr6.more_data?getnc_state->site_res->count:i, + r->out.ctr->ctr6.linked_attributes_count)); + +#if 0 + if (!r->out.ctr->ctr6.more_data) { + NDR_PRINT_FUNCTION_DEBUG(drsuapi_DsGetNCChanges, NDR_BOTH, r); + } +#endif return WERR_OK; } -- cgit From 340d7e807b2be7fb5c50a0cddf9378aa9bd929bf Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 10:27:03 +1100 Subject: s4-drs: fixed the UDV return in getncchanges We should overwrite an existing entry if found --- source4/rpc_server/drsuapi/getncchanges.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 84dc21d1b7..3189381d8e 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -447,6 +447,7 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx, NTTIME now; time_t t = time(NULL); struct replUpToDateVectorBlob ouv; + int i; werr = load_udv(sam_ctx, udv, ncRoot_dn, &ouv); if (!W_ERROR_IS_OK(werr)) { @@ -459,13 +460,24 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx, unix_to_nt_time(&now, t); tmp_cursor->last_sync_success = now; - udv->count = ouv.ctr.ctr2.count + 1; + udv->count = ouv.ctr.ctr2.count; udv->cursors = talloc_steal(udv, ouv.ctr.ctr2.cursors); - udv->cursors = talloc_realloc(udv, udv->cursors, struct drsuapi_DsReplicaCursor2, udv->count); - if (!udv->cursors) { - return WERR_DS_DRA_INTERNAL_ERROR; + + for (i=0; icount; i++) { + if (GUID_equal(&tmp_cursor->source_dsa_invocation_id, + &udv->cursors[i].source_dsa_invocation_id)) { + udv->cursors[i] = *tmp_cursor; + break; + } + } + if (i == udv->count) { + udv->cursors = talloc_realloc(udv, udv->cursors, struct drsuapi_DsReplicaCursor2, udv->count+1); + if (!udv->cursors) { + return WERR_DS_DRA_INTERNAL_ERROR; + } + udv->cursors[udv->count] = *tmp_cursor; + udv->count++; } - udv->cursors[udv->count - 1] = *tmp_cursor; qsort(udv->cursors, udv->count, sizeof(struct drsuapi_DsReplicaCursor2), -- cgit From dd33a22f1de513277ed1182f70eb81f16eaab543 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 11:53:09 +1100 Subject: s4-dsdb: use a common method for finding a link pair Use ^1 everywhere, to ensure it works for both forward and backward links --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index bf4a55054a..87868354a9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -216,7 +216,7 @@ static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_sche struct replmd_private *replmd_private = talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private); - target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1); + target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1); if (!target_attr) { /* * windows 2003 has a broken schema where the -- cgit From e1ffcfc7832768429e2f84ae048476ac0ff8dbba Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:03:11 +1100 Subject: s4-ldb: added ldb_module_get_ops() This is needed to support DSDB_FLAG_OWN_MODULE Pair-Programmed-With: Andrew Bartlett --- source4/lib/ldb/common/ldb_modules.c | 5 +++++ source4/lib/ldb/include/ldb_module.h | 1 + 2 files changed, 6 insertions(+) (limited to 'source4') diff --git a/source4/lib/ldb/common/ldb_modules.c b/source4/lib/ldb/common/ldb_modules.c index e79f072d50..e49d46a987 100644 --- a/source4/lib/ldb/common/ldb_modules.c +++ b/source4/lib/ldb/common/ldb_modules.c @@ -527,6 +527,11 @@ struct ldb_context *ldb_module_get_ctx(struct ldb_module *module) return module->ldb; } +const struct ldb_module_ops *ldb_module_get_ops(struct ldb_module *module) +{ + return module->ops; +} + void *ldb_module_get_private(struct ldb_module *module) { return module->private_data; diff --git a/source4/lib/ldb/include/ldb_module.h b/source4/lib/ldb/include/ldb_module.h index 0b0f863fec..2d14634ca8 100644 --- a/source4/lib/ldb/include/ldb_module.h +++ b/source4/lib/ldb/include/ldb_module.h @@ -140,6 +140,7 @@ const char * ldb_module_get_name(struct ldb_module *module); struct ldb_context *ldb_module_get_ctx(struct ldb_module *module); void *ldb_module_get_private(struct ldb_module *module); void ldb_module_set_private(struct ldb_module *module, void *private_data); +const struct ldb_module_ops *ldb_module_get_ops(struct ldb_module *module); int ldb_next_request(struct ldb_module *module, struct ldb_request *request); int ldb_next_start_trans(struct ldb_module *module); -- cgit From ca5c3a0a02b18787c089c4f32807d4cdf59578df Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 20:59:08 +1100 Subject: s4-dsdb: added DSDB_FLAG_OWN_MODULE This allows you to call dsdb_module_*() functions while including the current module in the module stack to be used Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/util.c | 52 +++++++++++++++++++++++++++++++++-- source4/dsdb/samdb/ldb_modules/util.h | 1 + 2 files changed, 50 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index fa451f4bcf..32b79a6701 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -211,7 +211,12 @@ int dsdb_module_search(struct ldb_module *module, return ret; } - ret = ldb_next_request(module, req); + if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { + const struct ldb_module_ops *ops = ldb_module_get_ops(module); + ret = ops->search(module, req); + } else { + ret = ldb_next_request(module, req); + } if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } @@ -262,6 +267,37 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx, return LDB_SUCCESS; } +/* + find a GUID given a DN. + */ +int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid) +{ + const char *attrs[] = { NULL }; + struct ldb_result *res; + TALLOC_CTX *tmp_ctx = talloc_new(module); + int ret; + NTSTATUS status; + + ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs, + DSDB_SEARCH_SHOW_DELETED| + DSDB_SEARCH_SHOW_EXTENDED_DN); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s", + ldb_dn_get_linearized(dn)); + talloc_free(tmp_ctx); + return ret; + } + + status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID"); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + /* a ldb_modify request operating on modules below the current module @@ -293,7 +329,12 @@ int dsdb_module_modify(struct ldb_module *module, } /* Run the new request */ - ret = ldb_next_request(module, mod_req); + if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { + const struct ldb_module_ops *ops = ldb_module_get_ops(module); + ret = ops->modify(module, mod_req); + } else { + ret = ldb_next_request(module, mod_req); + } if (ret == LDB_SUCCESS) { ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL); } @@ -336,7 +377,12 @@ int dsdb_module_rename(struct ldb_module *module, } /* Run the new request */ - ret = ldb_next_request(module, req); + if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { + const struct ldb_module_ops *ops = ldb_module_get_ops(module); + ret = ops->rename(module, req); + } else { + ret = ldb_next_request(module, req); + } if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h index 66579ab852..add39e110a 100644 --- a/source4/dsdb/samdb/ldb_modules/util.h +++ b/source4/dsdb/samdb/ldb_modules/util.h @@ -31,3 +31,4 @@ struct dsdb_attribute; #define DSDB_SEARCH_REVEAL_INTERNALS 0x0008 #define DSDB_SEARCH_SHOW_EXTENDED_DN 0x0010 #define DSDB_MODIFY_RELAX 0x0020 +#define DSDB_FLAG_OWN_MODULE 0x0040 -- cgit From d4853fed00a9f5e6e5eee5dc1ce0eab3cd9bda37 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 20:59:57 +1100 Subject: sd-schema: order DRS classes on the wire in reverse order windows sends objectclasses in DRS in the opposite order to what LDAP uses --- source4/dsdb/schema/schema_syntax.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index e958605707..0873779811 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -735,7 +735,10 @@ static WERROR _dsdb_syntax_OID_obj_ldb_to_drsuapi(struct ldb_context *ldb, blobs[i] = data_blob_talloc(blobs, NULL, 4); W_ERROR_HAVE_NO_MEMORY(blobs[i].data); - obj_class = dsdb_class_by_lDAPDisplayName(schema, (const char *)in->values[i].data); + /* in DRS windows puts the classes in the opposite + order to the order used in ldap */ + obj_class = dsdb_class_by_lDAPDisplayName(schema, + (const char *)in->values[(in->num_values-1)-i].data); if (!obj_class) { return WERR_FOOBAR; } -- cgit From 9f02898080f5a19930d9adfcce3cf4139e3952e9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:01:33 +1100 Subject: s4-schema: don't fill in the extended DN with a zero GUID sometimes windows sends us a zero GUID in a DRS DN. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/schema/schema_syntax.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index 0873779811..843b65d59d 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -1077,20 +1077,21 @@ WERROR dsdb_syntax_one_DN_drsuapi_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context W_ERROR_HAVE_NO_MEMORY(dn); } - status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return ntstatus_to_werror(status); - } + if (!GUID_all_zero(&id3.guid)) { + status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return ntstatus_to_werror(status); + } - ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return WERR_FOOBAR; + ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return WERR_FOOBAR; + } + talloc_free(guid_blob.data); } - talloc_free(guid_blob.data); - if (id3.__ndr_size_sid) { DATA_BLOB sid_blob; ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, iconv_convenience, &id3.sid, -- cgit From cb00e443a3c63889f39132e5e954eb0b95804e74 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:05:50 +1100 Subject: s4-drs: give a reason when an AddEntry commit fails Pair-Programmed-With: Andrew Bartlett --- source4/rpc_server/drsuapi/addentry.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/addentry.c b/source4/rpc_server/drsuapi/addentry.c index 89b664d691..ac94daa6a6 100644 --- a/source4/rpc_server/drsuapi/addentry.c +++ b/source4/rpc_server/drsuapi/addentry.c @@ -199,7 +199,8 @@ WERROR dcesrv_drsuapi_DsAddEntry(struct dcesrv_call_state *dce_call, TALLOC_CTX ret = ldb_transaction_commit(b_state->sam_ctx); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": DsAddEntry commit failed\n")); + DEBUG(0,(__location__ ": DsAddEntry commit failed: %s\n", + ldb_errstring(b_state->sam_ctx))); return WERR_DS_DRA_INTERNAL_ERROR; } -- cgit From 701148bbe9de178b068d200d086b1c6ba1045c97 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:06:56 +1100 Subject: s4-drs: we are doing the sorting for getncchanges in the app code now the sorting is quite delicate, and easier to get right in the getncchanges code Pair-Programmed-With: Andrew Bartlett --- source4/rpc_server/drsuapi/dcesrv_drsuapi.h | 1 - source4/rpc_server/drsuapi/drsutil.c | 21 --------------------- 2 files changed, 22 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h index e42d9569e7..3a64ef5c9c 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h @@ -57,7 +57,6 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb, struct ldb_dn *basedn, enum ldb_scope scope, const char * const *attrs, - const char *sort_attrib, const char *filter); WERROR drs_security_level_check(struct dcesrv_call_state *dce_call, diff --git a/source4/rpc_server/drsuapi/drsutil.c b/source4/rpc_server/drsuapi/drsutil.c index 43692ac5b4..0a8a576d60 100644 --- a/source4/rpc_server/drsuapi/drsutil.c +++ b/source4/rpc_server/drsuapi/drsutil.c @@ -47,7 +47,6 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb, struct ldb_dn *basedn, enum ldb_scope scope, const char * const *attrs, - const char *sort_attrib, const char *filter) { int ret; @@ -91,26 +90,6 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb, return ret; } - if (sort_attrib) { - struct ldb_server_sort_control **sort_control; - sort_control = talloc_array(req, struct ldb_server_sort_control *, 2); - if (sort_control == NULL) { - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } - sort_control[0] = talloc(req, struct ldb_server_sort_control); - sort_control[0]->attributeName = sort_attrib; - sort_control[0]->orderingRule = NULL; - sort_control[0]->reverse = 0; - sort_control[1] = NULL; - - ret = ldb_request_add_control(req, LDB_CONTROL_SERVER_SORT_OID, true, sort_control); - if (ret != LDB_SUCCESS) { - return ret; - } - } - - ret = ldb_request(ldb, req); if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); -- cgit From 7653f56bd48859dce2481ef1e7ee885b25bfc709 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:10:41 +1100 Subject: s4-drs: implemented sorting functions based on replication flags I think we probably have more work to do on the sort order, but this brings us a bit closer. --- source4/rpc_server/drsuapi/getncchanges.c | 45 +++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 3189381d8e..b48bc68293 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -486,6 +486,35 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx, return WERR_OK; } +/* + sort the objects we send by tree order + */ +static int site_res_cmp_parent_order(const struct ldb_message **m1, const struct ldb_message **m2) +{ + return ldb_dn_compare((*m2)->dn, (*m1)->dn); +} + +/* + sort the objects we send first by uSNChanged + */ +static int site_res_cmp_usn_order(const struct ldb_message **m1, const struct ldb_message **m2) +{ + unsigned usnchanged1, usnchanged2; + unsigned cn1, cn2; + cn1 = ldb_dn_get_comp_num((*m1)->dn); + cn2 = ldb_dn_get_comp_num((*m2)->dn); + if (cn1 != cn2) { + return cn1 > cn2 ? 1 : -1; + } + usnchanged1 = ldb_msg_find_attr_as_uint(*m1, "uSNChanged", 0); + usnchanged2 = ldb_msg_find_attr_as_uint(*m2, "uSNChanged", 0); + if (usnchanged1 == usnchanged2) { + return 0; + } + return usnchanged1 > usnchanged2 ? 1 : -1; +} + + /* state of a partially completed getncchanges call */ struct drsuapi_getncchanges_state { struct ldb_result *site_res; @@ -665,15 +694,27 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ scope = LDB_SCOPE_BASE; } - DEBUG(6,(__location__ ": getncchanges on %s using filter %s\n", + DEBUG(1,(__location__ ": getncchanges on %s using filter %s\n", ldb_dn_get_linearized(getnc_state->ncRoot_dn), search_filter)); ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, getnc_state, &getnc_state->site_res, getnc_state->ncRoot_dn, scope, attrs, - "uSNChanged", search_filter); if (ret != LDB_SUCCESS) { return WERR_DS_DRA_INTERNAL_ERROR; } + + if (req8->replica_flags & DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS) { + qsort(getnc_state->site_res->msgs, + getnc_state->site_res->count, + sizeof(getnc_state->site_res->msgs[0]), + (comparison_fn_t)site_res_cmp_parent_order); + } else { + qsort(getnc_state->site_res->msgs, + getnc_state->site_res->count, + sizeof(getnc_state->site_res->msgs[0]), + (comparison_fn_t)site_res_cmp_usn_order); + } + } /* Prefix mapping */ -- cgit From 5bf257fa9ba32ec31886be34edff35eb41f885d4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:12:19 +1100 Subject: s4-drs: use the extended linearized form for DRS replication We were sending zero GUIDs. Not good! Pair-Programmed-With: Andrew Bartlett --- source4/rpc_server/drsuapi/getncchanges.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index b48bc68293..18c9242a10 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -239,7 +239,6 @@ static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx, const struct dsdb_schema *schema, const struct dsdb_attribute *sa, struct ldb_message *msg, - struct ldb_message_element *el, struct dsdb_dn *dsdb_dn, struct drsuapi_DsReplicaLinkedAttribute **la_list, uint32_t *la_count) @@ -287,9 +286,9 @@ static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx, } /* we need a message_element with just one value in it */ - v = data_blob_string_const(dsdb_dn_get_linearized(*la_list, dsdb_dn)); + v = data_blob_string_const(dsdb_dn_get_extended_linearized(*la_list, dsdb_dn, 1)); - val_el = *el; + val_el.name = sa->lDAPDisplayName; val_el.values = &v; val_el.num_values = 1; @@ -298,7 +297,7 @@ static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx, if (drs.value_ctr.num_values != 1) { DEBUG(1,(__location__ ": Failed to build DRS blob for linked attribute %s in %s\n", - el->name, ldb_dn_get_linearized(msg->dn))); + sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn))); return WERR_DS_DRA_INTERNAL_ERROR; } @@ -379,7 +378,7 @@ static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx, } werr = get_nc_changes_add_la(mem_ctx, sam_ctx, schema, sa, msg, - el, dsdb_dn, la_list, la_count); + dsdb_dn, la_list, la_count); if (!W_ERROR_IS_OK(werr)) { talloc_free(tmp_ctx); return werr; -- cgit From ff6dd4a67fe74349a8e54766f2f0f91ded06a742 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:13:59 +1100 Subject: s4-drs: send all linked attributes at the end of a replication cycle This ensures that a link is not seen before the object it points to --- source4/rpc_server/drsuapi/getncchanges.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 18c9242a10..8ff5de5dc0 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -522,6 +522,8 @@ struct drsuapi_getncchanges_state { uint64_t min_usn; uint64_t highest_usn; struct ldb_dn *last_dn; + struct drsuapi_DsReplicaLinkedAttribute *la_list; + uint32_t la_count; }; /* @@ -782,13 +784,13 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ return werr; } - werr = get_nc_changes_add_links(b_state->sam_ctx, mem_ctx, + werr = get_nc_changes_add_links(b_state->sam_ctx, getnc_state, getnc_state->ncRoot_dn, schema, getnc_state->min_usn, req8->replica_flags, msg, - &r->out.ctr->ctr6.linked_attributes, - &r->out.ctr->ctr6.linked_attributes_count); + &getnc_state->la_list, + &getnc_state->la_count); if (!W_ERROR_IS_OK(werr)) { return werr; } @@ -842,6 +844,8 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ if (i < getnc_state->site_res->count) { r->out.ctr->ctr6.more_data = true; } else { + r->out.ctr->ctr6.linked_attributes_count = getnc_state->la_count; + r->out.ctr->ctr6.linked_attributes = talloc_steal(mem_ctx, getnc_state->la_list); r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx); r->out.ctr->ctr6.uptodateness_vector->version = 2; r->out.ctr->ctr6.uptodateness_vector->reserved1 = 0; -- cgit From 0c2afdd5a95c247eb8e7ce7d721ac61fb111220c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:16:35 +1100 Subject: s4-drs: update highwatermark after successfully encoding the object --- source4/rpc_server/drsuapi/getncchanges.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 8ff5de5dc0..cf4b637c0c 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -768,14 +768,6 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx); - uSN = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1); - if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) { - r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN; - } - if (uSN > getnc_state->highest_usn) { - getnc_state->highest_usn = uSN; - } - werr = get_nc_changes_build_object(obj, msg, b_state->sam_ctx, getnc_state->ncRoot_dn, schema, &session_key, getnc_state->min_usn, @@ -795,6 +787,14 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ return werr; } + uSN = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1); + if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) { + r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN; + } + if (uSN > getnc_state->highest_usn) { + getnc_state->highest_usn = uSN; + } + if (obj->meta_data_ctr == NULL) { DEBUG(0,(__location__ ": getncchanges skipping send of object %s\n", ldb_dn_get_linearized(msg->dn))); -- cgit From 0d5d7f58473c989bff4d7f7d65da31f9b037de3a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:18:31 +1100 Subject: s4-drs: treat a zero GUID as not present in replmd_add_fix_la Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 87868354a9..6e0c9b44e5 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -618,9 +618,12 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme /* note that the DN already has the extended components from the extended_dn_store module */ status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID"); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; + if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) { + ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false); -- cgit From 2e114484e5abd658b9a8ae1ecb1af6768bd8fc46 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:19:55 +1100 Subject: s4-drs: give an error message in repl_meta_data if we don't get a partition control --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 6e0c9b44e5..6804c1c764 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -318,6 +318,7 @@ static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares) } if (!partition_ctrl) { + ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply"); return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } -- cgit From e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:21:55 +1100 Subject: s4-drs: cope better with NULL GUIDS from DRS It is valid to get a NULL GUID over DRS for a deleted forward link. We need to match by DN if possible when seeing if we should update an existing link. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 36 +++++++++++++++++-------- 1 file changed, 25 insertions(+), 11 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 6804c1c764..8603e1c3dd 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1107,9 +1107,21 @@ static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2) return GUID_compare(pdn1->guid, pdn2->guid); } -static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid) +static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid, struct ldb_dn *dn) { struct parsed_dn *ret; + if (dn && GUID_all_zero(guid)) { + /* when updating a link using DRS, we sometimes get a + NULL GUID. We then need to try and match by DN */ + int i; + for (i=0; idn, dn) == 0) { + dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID"); + return &pdn[i]; + } + } + return NULL; + } BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret); return ret; } @@ -1443,7 +1455,7 @@ static int replmd_modify_la_add(struct ldb_module *module, /* for each new value, see if it exists already with the same GUID */ for (i=0; inum_values; i++) { - struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid); + struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL); if (p == NULL) { /* this is a new linked attribute value */ new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1); @@ -1575,7 +1587,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, struct parsed_dn *p2; const struct ldb_val *v; - p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid); + p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL); if (!p2) { ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s", el->name, GUID_string(tmp_ctx, p->guid)); @@ -1596,7 +1608,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, struct parsed_dn *p = &old_dns[i]; const struct ldb_val *v; - if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) { + if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) { continue; } @@ -1699,7 +1711,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, return ret; } - p = parsed_dn_find(dns, el->num_values, old_p->guid); + p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL); if (p) { /* we don't delete it if we are re-adding it */ continue; @@ -1721,7 +1733,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, if (old_dns && (old_p = parsed_dn_find(old_dns, - old_num_values, p->guid)) != NULL) { + old_num_values, p->guid, NULL)) != NULL) { /* update in place */ ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, invocation_id, @@ -3325,7 +3337,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module, struct ldb_result *res; const char *attrs[2]; struct parsed_dn *pdn_list, *pdn; - struct GUID guid; + struct GUID guid = GUID_zero(); NTSTATUS ntstatus; bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false; const struct GUID *our_invocation_id; @@ -3455,14 +3467,16 @@ linked_attributes[0]: } ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID"); - if (!NT_STATUS_IS_OK(ntstatus)) { - ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s\n", - old_el->name, ldb_dn_get_linearized(msg->dn)); + if (!NT_STATUS_IS_OK(ntstatus) && active) { + ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s", + old_el->name, + ldb_dn_get_linearized(dsdb_dn->dn), + ldb_dn_get_linearized(msg->dn)); return LDB_ERR_OPERATIONS_ERROR; } /* see if this link already exists */ - pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid); + pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn); if (pdn != NULL) { /* see if this update is newer than what we have already */ struct GUID invocation_id = GUID_zero(); -- cgit From 7a39340c8ecf4ac9475ae91f721dc979b19c030d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:23:18 +1100 Subject: s4-drs: use dsdb_module_guid_by_dn() We should not be going to the top of the module stack --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 8603e1c3dd..4f3ce01cd0 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1172,7 +1172,7 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID"); if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { /* we got a DN without a GUID - go find the GUID */ - int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid); + int ret = dsdb_module_guid_by_dn(module, dn, p->guid); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n", ldb_dn_get_linearized(dn)); -- cgit From 5b31cb20dd49622fa761fd4ae1869bcc0de0330d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:24:18 +1100 Subject: s4-drs: fixed typo for uSNCreated This broke DRS replication from samba to windows Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 4f3ce01cd0..ba9a9bf3a9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2192,7 +2192,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid", "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName", "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection", - "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreate", + "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated", NULL}; uint32_t el_count = 0; int i; -- cgit From 9572535940e808d4dd681ee01b04ad589c7e73c9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:25:27 +1100 Subject: s4-drs: update comment to refect only forward link in this fn This function only update forward links Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index ba9a9bf3a9..ed0a96b14f 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2088,8 +2088,10 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are return ldb_next_request(ac->module, down_req); } -/* remove forwards and backlinks as needed when an object - is deleted */ +/* + remove links from objects that point at this object when an object + is deleted + */ static int replmd_delete_remove_link(struct ldb_module *module, struct dsdb_schema *schema, struct ldb_dn *dn, -- cgit From 530503290d029894d3b0f0bc4f3c058752e904fb Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:26:15 +1100 Subject: s4-drs: use DSDB_FLAG_OWN_MODULE We need DRS driven replication changes to update replPropertyMetaData, so it needs to call into the repl_meta_data module logic Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index ed0a96b14f..ae7dcc1954 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2154,7 +2154,7 @@ static int replmd_delete_remove_link(struct ldb_module *module, el2->values = &dn_val; el2->num_values = 1; - ret = dsdb_module_modify(module, msg, 0); + ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2354,8 +2354,8 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) el->flags = LDB_FLAG_MOD_REPLACE; } - ret = dsdb_module_modify(module, msg, 0); - if (ret != LDB_SUCCESS){ + ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE); + if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s", ldb_dn_get_linearized(old_dn), ldb_errstring(ldb)); talloc_free(tmp_ctx); -- cgit From 0bf7f952735e848700122c9ced064d211831ba7c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:27:16 +1100 Subject: s4-drs: isRecycled only exists in FL W2K8-R2 Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index ae7dcc1954..9994b9566d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2280,6 +2280,19 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) } msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD; + /* we also mark it as recycled, meaning this object can't be + recovered (we are stripping its attributes) */ + if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) { + ret = ldb_msg_add_string(msg, "isRecycled", "TRUE"); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n")); + ldb_module_oom(module); + talloc_free(tmp_ctx); + return ret; + } + msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD; + } + /* we need the storage form of the parent GUID */ ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res, ldb_dn_get_parent(tmp_ctx, old_dn), NULL, -- cgit From 9f053d43ded23bb72d4c10162a8c6a211831b068 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:28:04 +1100 Subject: s4-drs: don't try to remove backlinks directly backlinks need to be removed as a side effect of removing the forward link Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 9994b9566d..5bf43857cc 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2327,12 +2327,13 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) continue; } - if (sa->linkID) { + if (sa->linkID && sa->linkID & 1) { ret = replmd_delete_remove_link(module, schema, old_dn, el, sa); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } + continue; } if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) { -- cgit From db3f0e8ec1bfc6d3f27195ee38f53489501e731e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 22 Dec 2009 12:21:02 +1100 Subject: s4-dsdb: fixed valgrind error in replmd modify We are using the values from a search result, so we need to steal them onto the msg before we free the search results Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 5bf43857cc..3c713ec4d9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1880,7 +1880,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, } ldb_msg_add_empty(old_msg, el->name, 0, &new_el); new_el->num_values = el->num_values; - new_el->values = el->values; + new_el->values = talloc_steal(msg->elements, el->values); /* TODO: this relises a bit too heavily on the exact behaviour of ldb_msg_find_element and -- cgit From 36f8ece9de5e5bd9f885bba84ac6377c1ed8f7a9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 22 Dec 2009 12:31:42 +1100 Subject: s4-ldb: show the error code as well as errstr Pair-Programmed-With: Andrew Bartlett --- source4/lib/ldb/tools/ldbadd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/tools/ldbadd.c b/source4/lib/ldb/tools/ldbadd.c index 4ff07a5bef..e618ab52f7 100644 --- a/source4/lib/ldb/tools/ldbadd.c +++ b/source4/lib/ldb/tools/ldbadd.c @@ -72,8 +72,9 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls); if (ret != LDB_SUCCESS) { - fprintf(stderr, "ERR: \"%s\" on DN %s\n", - ldb_errstring(ldb), ldb_dn_get_linearized(ldif->msg->dn)); + fprintf(stderr, "ERR: %s : \"%s\" on DN %s\n", + ldb_strerror(ret), ldb_errstring(ldb), + ldb_dn_get_linearized(ldif->msg->dn)); failures++; } else { (*count)++; -- cgit From a81dd03917b5ae74b3b5515cbb37cbafaecc5c28 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 14:11:37 +1100 Subject: s4-drs: set flag to indicate that we do support linked attributes --- source4/rpc_server/drsuapi/dcesrv_drsuapi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c index 3d92880162..6a6bc8be7e 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c @@ -159,10 +159,7 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2; - if (0 /*domain.behavior_version == 2*/) { - /* TODO: find out how this is really triggered! */ - b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; - } + b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND; -- cgit From 5e52c7149fb6f4e79541cde719f7f014d8954922 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 17:18:14 +1100 Subject: s4-dsdb: added parse functions for DRS linked attribute blobs --- source4/dsdb/common/dsdb_dn.c | 69 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/common/dsdb_dn.c b/source4/dsdb/common/dsdb_dn.c index 660eaf7d40..9023b0347a 100644 --- a/source4/dsdb/common/dsdb_dn.c +++ b/source4/dsdb/common/dsdb_dn.c @@ -325,3 +325,72 @@ int dsdb_dn_string_comparison(struct ldb_context *ldb, void *mem_ctx, { return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_string_canonicalise, v1, v2); } + + +/* + convert a dsdb_dn to a linked attribute data blob +*/ +WERROR dsdb_dn_la_to_blob(struct ldb_context *sam_ctx, + const struct dsdb_attribute *schema_attrib, + const struct dsdb_schema *schema, + TALLOC_CTX *mem_ctx, + struct dsdb_dn *dsdb_dn, DATA_BLOB **blob) +{ + struct ldb_val v; + WERROR werr; + struct ldb_message_element val_el; + struct drsuapi_DsReplicaAttribute drs; + + /* we need a message_element with just one value in it */ + v = data_blob_string_const(dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1)); + + val_el.name = schema_attrib->lDAPDisplayName; + val_el.values = &v; + val_el.num_values = 1; + + werr = schema_attrib->syntax->ldb_to_drsuapi(sam_ctx, schema, schema_attrib, &val_el, mem_ctx, &drs); + W_ERROR_NOT_OK_RETURN(werr); + + if (drs.value_ctr.num_values != 1) { + DEBUG(1,(__location__ ": Failed to build DRS blob for linked attribute %s\n", + schema_attrib->lDAPDisplayName)); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + *blob = drs.value_ctr.values[0].blob; + return WERR_OK; +} + +/* + convert a data blob to a dsdb_dn + */ +WERROR dsdb_dn_la_from_blob(struct ldb_context *sam_ctx, + const struct dsdb_attribute *schema_attrib, + const struct dsdb_schema *schema, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob, + struct dsdb_dn **dsdb_dn) +{ + WERROR werr; + struct ldb_message_element new_el; + struct drsuapi_DsReplicaAttribute drs; + struct drsuapi_DsAttributeValue val; + + drs.value_ctr.num_values = 1; + drs.value_ctr.values = &val; + val.blob = blob; + + werr = schema_attrib->syntax->drsuapi_to_ldb(sam_ctx, schema, schema_attrib, &drs, mem_ctx, &new_el); + W_ERROR_NOT_OK_RETURN(werr); + + if (new_el.num_values != 1) { + return WERR_INTERNAL_ERROR; + } + + *dsdb_dn = dsdb_dn_parse(mem_ctx, sam_ctx, &new_el.values[0], schema_attrib->syntax->ldap_oid); + if (!*dsdb_dn) { + return WERR_INTERNAL_ERROR; + } + + return WERR_OK; +} -- cgit From 38160deac4d6f4a8ae22fcedcf55114bc0372f31 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 17:19:29 +1100 Subject: s4-drs: use dsdb linked attribute parse functions This makes the code considerably more readable --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 27 ++++--------------------- source4/rpc_server/drsuapi/getncchanges.c | 20 +----------------- 2 files changed, 5 insertions(+), 42 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3c713ec4d9..baae44a30d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3345,9 +3345,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module, const struct dsdb_attribute *attr; struct dsdb_dn *dsdb_dn; uint64_t seq_num = 0; - struct drsuapi_DsReplicaAttribute drs; - struct drsuapi_DsAttributeValue val; - struct ldb_message_element new_el, *old_el; + struct ldb_message_element *old_el; WERROR status; time_t t = time(NULL); struct ldb_result *res; @@ -3358,10 +3356,6 @@ static int replmd_process_linked_attribute(struct ldb_module *module, bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false; const struct GUID *our_invocation_id; - drs.value_ctr.num_values = 1; - drs.value_ctr.values = &val; - val.blob = la->value.blob; - /* linked_attributes[0]: &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute @@ -3462,23 +3456,10 @@ linked_attributes[0]: return ret; } - status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el); + status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn); if (!W_ERROR_IS_OK(status)) { - ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n", - old_el->name, ldb_dn_get_linearized(msg->dn)); - return LDB_ERR_OPERATIONS_ERROR; - } - - if (new_el.num_values != 1) { - ldb_asprintf_errstring(ldb, "Failed to find value in linked attribute blob for %s on %s\n", - old_el->name, ldb_dn_get_linearized(msg->dn)); - return LDB_ERR_OPERATIONS_ERROR; - } - - dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &new_el.values[0], attr->syntax->ldap_oid); - if (!dsdb_dn) { - ldb_asprintf_errstring(ldb, "Failed to parse DN in linked attribute blob for %s on %s\n", - old_el->name, ldb_dn_get_linearized(msg->dn)); + ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status)); return LDB_ERR_OPERATIONS_ERROR; } diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index cf4b637c0c..dc4483c8f8 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -246,10 +246,7 @@ static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx, struct drsuapi_DsReplicaLinkedAttribute *la; bool active; NTSTATUS status; - struct ldb_message_element val_el; - struct ldb_val v; WERROR werr; - struct drsuapi_DsReplicaAttribute drs; (*la_list) = talloc_realloc(mem_ctx, *la_list, struct drsuapi_DsReplicaLinkedAttribute, (*la_count)+1); W_ERROR_HAVE_NO_MEMORY(*la_list); @@ -285,24 +282,9 @@ static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx, return ntstatus_to_werror(status); } - /* we need a message_element with just one value in it */ - v = data_blob_string_const(dsdb_dn_get_extended_linearized(*la_list, dsdb_dn, 1)); - - val_el.name = sa->lDAPDisplayName; - val_el.values = &v; - val_el.num_values = 1; - - werr = sa->syntax->ldb_to_drsuapi(sam_ctx, schema, sa, &val_el, *la_list, &drs); + werr = dsdb_dn_la_to_blob(sam_ctx, sa, schema, *la_list, dsdb_dn, &la->value.blob); W_ERROR_NOT_OK_RETURN(werr); - if (drs.value_ctr.num_values != 1) { - DEBUG(1,(__location__ ": Failed to build DRS blob for linked attribute %s in %s\n", - sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn))); - return WERR_DS_DRA_INTERNAL_ERROR; - } - - la->value.blob = drs.value_ctr.values[0].blob; - (*la_count)++; return WERR_OK; } -- cgit From 5dd6e089f136d3ce04127b930da59913704bf083 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 17:20:13 +1100 Subject: s4-drs: use dsdb_module_rename() Use the new dsdb_module_rename() for DRS rename handling, instead of ldb_rename(). This stops us going to the top of the module stack on a rename. --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index baae44a30d..b9d9a744f1 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2571,10 +2571,9 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n", ldb_dn_get_linearized(ar->search_msg->dn), ldb_dn_get_linearized(msg->dn)); - /* we can't use dsdb_module_rename() here as we need - the rename call to be intercepted by this module, to - allow it to process linked attribute changes */ - if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) { + if (dsdb_module_rename(ar->module, + ar->search_msg->dn, msg->dn, + DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n", ldb_dn_get_linearized(ar->search_msg->dn), ldb_dn_get_linearized(msg->dn), -- cgit From d48237d547470e064b7f5fb464758e7e9eaae17d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 17:22:12 +1100 Subject: s4-drs: re-resolve the DN in linked attribute processing w2k8-r2 sometimes sends the DN with an old target --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index b9d9a744f1..991d8c314d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3471,6 +3471,16 @@ linked_attributes[0]: return LDB_ERR_OPERATIONS_ERROR; } + /* re-resolve the DN by GUID, as the DRS server may give us an + old DN value */ + ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": Failed to re-resolve GUID %s", + GUID_string(tmp_ctx, &guid)); + talloc_free(tmp_ctx); + return ret; + } + /* see if this link already exists */ pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn); if (pdn != NULL) { -- cgit From e3cf818c277f90df37cab8a2ecbf93e6a92d8cb2 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 17:22:40 +1100 Subject: s4-drs: sort linked attributes See MS-DRSR section 4.1.10.5.17 for a description of the sorting comparison function --- source4/rpc_server/drsuapi/getncchanges.c | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index dc4483c8f8..a41d116b6a 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -467,6 +467,74 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx, return WERR_OK; } + +/* comparison function for linked attributes - see CompareLinks() in + * MS-DRSR section 4.1.10.5.17 */ +static int linked_attribute_compare(const struct drsuapi_DsReplicaLinkedAttribute *la1, + const struct drsuapi_DsReplicaLinkedAttribute *la2, + struct ldb_context *sam_ctx) +{ + int c; + WERROR werr; + TALLOC_CTX *tmp_ctx; + const struct dsdb_schema *schema; + const struct dsdb_attribute *schema_attrib; + struct dsdb_dn *dn1, *dn2; + struct GUID guid1, guid2; + NTSTATUS status; + + c = GUID_compare(&la1->identifier->guid, + &la2->identifier->guid); + if (c != 0) return c; + + if (la1->attid != la2->attid) { + return la1->attid < la2->attid? -1:1; + } + + if ((la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) != + (la2->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) { + return (la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)? 1:-1; + } + + /* we need to get the target GUIDs to compare */ + tmp_ctx = talloc_new(sam_ctx); + + schema = dsdb_get_schema(sam_ctx); + schema_attrib = dsdb_attribute_by_attributeID_id(schema, la1->attid); + + werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la1->value.blob, &dn1); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(0,(__location__ ": Bad la1 blob in sort\n")); + talloc_free(tmp_ctx); + return 0; + } + + werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la2->value.blob, &dn2); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(0,(__location__ ": Bad la2 blob in sort\n")); + talloc_free(tmp_ctx); + return 0; + } + + status = dsdb_get_extended_dn_guid(dn1->dn, &guid1, "GUID"); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,(__location__ ": Bad la1 guid in sort\n")); + talloc_free(tmp_ctx); + return 0; + } + status = dsdb_get_extended_dn_guid(dn2->dn, &guid2, "GUID"); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,(__location__ ": Bad la2 guid in sort\n")); + talloc_free(tmp_ctx); + return 0; + } + + talloc_free(tmp_ctx); + + return GUID_compare(&guid1, &guid2); +} + + /* sort the objects we send by tree order */ @@ -828,6 +896,11 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ } else { r->out.ctr->ctr6.linked_attributes_count = getnc_state->la_count; r->out.ctr->ctr6.linked_attributes = talloc_steal(mem_ctx, getnc_state->la_list); + + ldb_qsort(r->out.ctr->ctr6.linked_attributes, r->out.ctr->ctr6.linked_attributes_count, + sizeof(r->out.ctr->ctr6.linked_attributes[0]), + b_state->sam_ctx, (ldb_qsort_cmp_fn_t)linked_attribute_compare); + r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx); r->out.ctr->ctr6.uptodateness_vector->version = 2; r->out.ctr->ctr6.uptodateness_vector->reserved1 = 0; -- cgit From baae6ef9d24a59f794a8cbc9aa0ccdbbeb2ed369 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 29 Dec 2009 11:36:37 +1100 Subject: s4-ldb: added ldb_val_to_time() This is intended as a replacement for ldb_string_to_time() for ldb_val inputs. This ensures it is length limited and includes additional validity checks --- source4/lib/ldb/common/ldb_msg.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'source4') diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c index fbf49fbb23..9b33d7e351 100644 --- a/source4/lib/ldb/common/ldb_msg.c +++ b/source4/lib/ldb/common/ldb_msg.c @@ -831,6 +831,33 @@ time_t ldb_string_to_time(const char *s) return timegm(&tm); } +/* + convert a LDAP GeneralizedTime string in ldb_val format to a + time_t. +*/ +int ldb_val_to_time(const struct ldb_val *v, time_t *t) +{ + struct tm tm; + + if (v == NULL || !v->data || v->length < 14) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + + memset(&tm, 0, sizeof(tm)); + + if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + *t = timegm(&tm); + + return LDB_SUCCESS; +} + /* return a LDAP formatted UTCTime string */ -- cgit From c3061794ef4d03d5b26d4a221a93722b3ed08197 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 29 Dec 2009 11:37:17 +1100 Subject: s4-dsdb: use ldb_val_to_time() instead of ldb_string_to_time() --- source4/dsdb/samdb/ldb_modules/simple_ldap_map.c | 6 +++--- source4/dsdb/schema/schema_syntax.c | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c index 43402248c0..bf9cd4fdda 100644 --- a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c +++ b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c @@ -181,7 +181,7 @@ static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val) { - char *entryCSN = talloc_strdup(ctx, (const char *)val->data); + char *entryCSN = talloc_strndup(ctx, (const char *)val->data, val->length); char *mod_per_sec; time_t t; unsigned long long usn; @@ -232,10 +232,10 @@ static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ct static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val) { struct ldb_val out; - time_t t; + time_t t=0; unsigned long long usn; - t = ldb_string_to_time((const char *)val->data); + ldb_val_to_time(val, &t); usn = ((unsigned long long)t <<24); diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index 843b65d59d..de52b9c628 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -488,13 +488,17 @@ static WERROR dsdb_syntax_NTTIME_ldb_to_drsuapi(struct ldb_context *ldb, for (i=0; i < in->num_values; i++) { NTTIME v; time_t t; + int ret; out->value_ctr.values[i].blob = &blobs[i]; blobs[i] = data_blob_talloc(blobs, NULL, 8); W_ERROR_HAVE_NO_MEMORY(blobs[i].data); - t = ldb_string_to_time((const char *)in->values[i].data); + ret = ldb_val_to_time(&in->values[i], &t); + if (ret != LDB_SUCCESS) { + return WERR_DS_INVALID_ATTRIBUTE_SYNTAX; + } unix_to_nt_time(&v, t); v /= 10000000; -- cgit From 708ad42b0b1029a813141d1b1d14c782f7ce6393 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 29 Dec 2009 11:38:17 +1100 Subject: s4-dsdb: use safe length limiting in string->integer conversion The ldap.py test suite could trigger a read past the end of the struct ldb_val buffer --- source4/lib/ldb-samba/ldif_handlers.c | 46 ++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 11 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb-samba/ldif_handlers.c b/source4/lib/ldb-samba/ldif_handlers.c index 39fc93af95..7ddc8e57a7 100644 --- a/source4/lib/ldb-samba/ldif_handlers.c +++ b/source4/lib/ldb-samba/ldif_handlers.c @@ -678,20 +678,43 @@ static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx, v1, v2); } -/* Canonicalisation of two 32-bit integers */ -static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx, - const struct ldb_val *in, struct ldb_val *out) +/* length limited conversion of a ldb_val to a int32_t */ +static int val_to_int32(const struct ldb_val *in, int32_t *v) { char *end; + char buf[64]; + + /* make sure we don't read past the end of the data */ + if (in->length > sizeof(buf)-1) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + strncpy(buf, (char *)in->data, in->length); + buf[in->length] = 0; + /* We've to use "strtoll" here to have the intended overflows. * Otherwise we may get "LONG_MAX" and the conversion is wrong. */ - int32_t i = (int32_t) strtoll((char *)in->data, &end, 0); + *v = (int32_t) strtoll(buf, &end, 0); if (*end != 0) { - return -1; + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + return LDB_SUCCESS; +} + +/* Canonicalisation of two 32-bit integers */ +static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) +{ + int32_t i; + int ret; + + ret = val_to_int32(in, &i); + if (ret != LDB_SUCCESS) { + return ret; } out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i); if (out->data == NULL) { - return -1; + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; } out->length = strlen((char *)out->data); return 0; @@ -699,12 +722,13 @@ static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx, /* Comparison of two 32-bit integers */ static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx, - const struct ldb_val *v1, const struct ldb_val *v2) + const struct ldb_val *v1, const struct ldb_val *v2) { - /* We've to use "strtoll" here to have the intended overflows. - * Otherwise we may get "LONG_MAX" and the conversion is wrong. */ - return (int32_t) strtoll((char *)v1->data, NULL, 0) - - (int32_t) strtoll((char *)v2->data, NULL, 0); + int32_t i1=0, i2=0; + val_to_int32(v1, &i1); + val_to_int32(v2, &i2); + if (i1 == i2) return 0; + return i1 > i2? 1 : -1; } /* -- cgit From 53e86ac5b27e7e5d13ab671b8ce202bb97b80d3e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 29 Dec 2009 11:38:49 +1100 Subject: s4-ldb: use safe length limited conversions for int64 and time --- source4/lib/ldb/common/attrib_handlers.c | 61 +++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 13 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/common/attrib_handlers.c b/source4/lib/ldb/common/attrib_handlers.c index 1c08741f7d..464707530e 100644 --- a/source4/lib/ldb/common/attrib_handlers.c +++ b/source4/lib/ldb/common/attrib_handlers.c @@ -100,6 +100,27 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, return 0; } +/* length limited conversion of a ldb_val to a int32_t */ +static int val_to_int64(const struct ldb_val *in, int64_t *v) +{ + char *end; + char buf[64]; + + /* make sure we don't read past the end of the data */ + if (in->length > sizeof(buf)-1) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + strncpy(buf, (char *)in->data, in->length); + buf[in->length] = 0; + + /* We've to use "strtoll" here to have the intended overflows. + * Otherwise we may get "LONG_MAX" and the conversion is wrong. */ + *v = (int64_t) strtoll(buf, &end, 0); + if (*end != 0) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + return LDB_SUCCESS; +} /* @@ -109,14 +130,17 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *in, struct ldb_val *out) { - char *end; - long long i = strtoll((char *)in->data, &end, 0); - if (*end != 0) { - return -1; + int64_t i; + int ret; + + ret = val_to_int64(in, &i); + if (ret != LDB_SUCCESS) { + return ret; } - out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i); + out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i); if (out->data == NULL) { - return -1; + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; } out->length = strlen((char *)out->data); return 0; @@ -128,7 +152,11 @@ static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx, static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *v1, const struct ldb_val *v2) { - return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0); + int64_t i1=0, i2=0; + val_to_int64(v1, &i1); + val_to_int64(v2, &i2); + if (i1 == i2) return 0; + return i1 > i2? 1 : -1; } /* @@ -338,10 +366,11 @@ static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx, static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *v1, const struct ldb_val *v2) { - time_t t1, t2; - t1 = ldb_string_to_time((char *)v1->data); - t2 = ldb_string_to_time((char *)v2->data); - return (int)t2 - (int)t1; + time_t t1=0, t2=0; + ldb_val_to_time(v1, &t1); + ldb_val_to_time(v2, &t2); + if (t1 == t2) return 0; + return t1 > t2? 1 : -1; } /* @@ -350,10 +379,16 @@ static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx, static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *in, struct ldb_val *out) { - time_t t = ldb_string_to_time((char *)in->data); + time_t t; + int ret; + ret = ldb_val_to_time(in, &t); + if (ret != LDB_SUCCESS) { + return ret; + } out->data = (uint8_t *)ldb_timestring(mem_ctx, t); if (out->data == NULL) { - return -1; + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; } out->length = strlen((char *)out->data); return 0; -- cgit From 1ab5020ef238d73d23611ef1da22d14c8ab3dbcc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 29 Dec 2009 11:39:05 +1100 Subject: s4-ldb: declate ldb_val_to_time() --- source4/lib/ldb/include/ldb.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source4') diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index c8bfa24832..1958fd740b 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -1950,6 +1950,12 @@ char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t); */ time_t ldb_string_to_time(const char *s); +/** + convert a LDAP GeneralizedTime string in ldb_val format to a + time_t. +*/ +int ldb_val_to_time(const struct ldb_val *v, time_t *t); + /** Convert a time structure to a string -- cgit From 302dcd022633a928050c916561a6f640216fb247 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 29 Dec 2009 11:39:29 +1100 Subject: s4-ldbmodify: show the error code as well as error string --- source4/lib/ldb/tools/ldbmodify.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/lib/ldb/tools/ldbmodify.c b/source4/lib/ldb/tools/ldbmodify.c index 575658600c..57988cbb30 100644 --- a/source4/lib/ldb/tools/ldbmodify.c +++ b/source4/lib/ldb/tools/ldbmodify.c @@ -73,7 +73,8 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) break; } if (ret != LDB_SUCCESS) { - fprintf(stderr, "ERR: \"%s\" on DN %s\n", + fprintf(stderr, "ERR: (%s) \"%s\" on DN %s\n", + ldb_strerror(ret), ldb_errstring(ldb), ldb_dn_get_linearized(ldif->msg->dn)); failures++; } else { -- cgit From 81e8a18181d3f24ac837ae0295fc2fca927a7ddf Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 29 Dec 2009 11:40:30 +1100 Subject: s4-ldb: allow modules to override error return values The samldb module overrides the error code for some returns when handling primaryGroupID. We need to take the error from the async callback to allow this to work reliably --- source4/lib/ldb/common/ldb_modules.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/common/ldb_modules.c b/source4/lib/ldb/common/ldb_modules.c index e49d46a987..5e9d0e6e98 100644 --- a/source4/lib/ldb/common/ldb_modules.c +++ b/source4/lib/ldb/common/ldb_modules.c @@ -606,7 +606,7 @@ int ldb_next_request(struct ldb_module *module, struct ldb_request *request) * all our modules, and leaves us one less sharp * corner for module developers to cut themselves on */ - ldb_module_done(request, NULL, NULL, ret); + ret = ldb_module_done(request, NULL, NULL, ret); } return ret; } @@ -830,7 +830,9 @@ int ldb_module_done(struct ldb_request *req, } req->callback(req, ares); - return error; + /* returning ares->error here allows the callback routines in + modules to override the error code */ + return ares->error; } /* to be used *only* in modules init functions. -- cgit From 98d94cca6fdf0f9fbe045fdb213f642244ddc41f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 29 Dec 2009 11:41:19 +1100 Subject: s4-ldbtest: fixed message element in modify a flags value of zero is not valid --- source4/lib/ldb/tests/python/ldap.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py index c2920c009e..36514f1262 100755 --- a/source4/lib/ldb/tests/python/ldap.py +++ b/source4/lib/ldb/tests/python/ldap.py @@ -704,7 +704,8 @@ objectClass: container # Make group 1 secondary m = Message() m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn) - m["member"] = "cn=ldaptestuser,cn=users," + self.base_dn + m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn, + FLAG_MOD_REPLACE, "member") ldb.modify(m) # Make group 1 primary -- cgit From 6628588dfba353c3d2948d14de2d24edfafc371d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 10:52:14 +1100 Subject: s4-dsdb: added dsdb_set_extended_dn_guid() --- source4/dsdb/common/util.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index ef47079f9f..25d915d0bc 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2794,6 +2794,25 @@ int dsdb_functional_level(struct ldb_context *ldb) return *domainFunctionality; } +/* + set a GUID in an extended DN structure + */ +int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name) +{ + struct ldb_val v; + NTSTATUS status; + int ret; + + status = GUID_to_ndr_blob(guid, dn, &v); + if (!NT_STATUS_IS_OK(status)) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + + ret = ldb_dn_set_extended_component(dn, component_name, &v); + data_blob_free(&v); + return ret; +} + /* return a GUID from a extended DN structure */ -- cgit From 4eecfc80bc7f305cc6c57ebc2a56f2aa354a522f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 10:52:55 +1100 Subject: s4-drs: make sure the DNs we put in the db have a extended GUID --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 991d8c314d..f12b62c14b 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -609,13 +609,6 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme NTSTATUS status; int ret; - ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, - seq_num, seq_num, now, 0, false); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; - } - /* note that the DN already has the extended components from the extended_dn_store module */ status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID"); @@ -625,6 +618,18 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme talloc_free(tmp_ctx); return ret; } + ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID"); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, + seq_num, seq_num, now, 0, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; } ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false); @@ -1178,6 +1183,10 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, ldb_dn_get_linearized(dn)); return ret; } + ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID"); + if (ret != LDB_SUCCESS) { + return ret; + } } else if (!NT_STATUS_IS_OK(status)) { return LDB_ERR_OPERATIONS_ERROR; } -- cgit From e410a91ff423213feeee52b7357bd95e5f7f4552 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 10:53:36 +1100 Subject: s4-ldb: show an error string, as well as error message This makes it easier to track down error mismatches from the test suite --- source4/lib/ldb/tools/ldbdel.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/tools/ldbdel.c b/source4/lib/ldb/tools/ldbdel.c index 4238f35067..6de15ee042 100644 --- a/source4/lib/ldb/tools/ldbdel.c +++ b/source4/lib/ldb/tools/ldbdel.c @@ -121,9 +121,10 @@ int main(int argc, const char **argv) } } if (ret != 0) { - printf("delete of '%s' failed - %s\n", - ldb_dn_get_linearized(dn), - ldb_errstring(ldb)); + printf("delete of '%s' failed - (%s) %s\n", + ldb_dn_get_linearized(dn), + ldb_strerror(ret), + ldb_errstring(ldb)); } } -- cgit From 1c5a268f34af7fdb4fcbd7f94898a1e76aa142b7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 10:54:03 +1100 Subject: s4-ldaptest: need to use MessageElement for modify messages Without MessageElement() the flags are not set, which is invalid --- source4/lib/ldb/tests/python/ldap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py index 36514f1262..c90727d720 100755 --- a/source4/lib/ldb/tests/python/ldap.py +++ b/source4/lib/ldb/tests/python/ldap.py @@ -725,7 +725,8 @@ objectClass: container # Try to add group 1 also as secondary - should be denied m = Message() m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn) - m["member"] = "cn=ldaptestuser,cn=users," + self.base_dn + m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn, + FLAG_MOD_ADD, "member") try: ldb.modify(m) self.fail() @@ -747,7 +748,8 @@ objectClass: container # Make group 2 secondary m = Message() m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn) - m["member"] = "cn=ldaptestuser,cn=users," + self.base_dn + m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn, + FLAG_MOD_ADD, "member") ldb.modify(m) # Swap the groups -- cgit From 23eb9f49a75f599a78d2f70fb4b864f1e0c6e0a1 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 18:47:51 +1100 Subject: s4-dsdb: allow system to remove deleted objects This will be used by a periodic job to remove tombstoned objects --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index f12b62c14b..ab412942e9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -47,6 +47,7 @@ #include "lib/util/dlinklist.h" #include "dsdb/samdb/ldb_modules/util.h" #include "lib/util/binsearch.h" +#include "libcli/security/security.h" #define W2K3_LINKED_ATTRIBUTES 1 @@ -2208,6 +2209,10 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) uint32_t el_count = 0; int i; + if (ldb_dn_is_special(req->op.del.dn)) { + return ldb_next_request(module, req); + } + tmp_ctx = talloc_new(ldb); old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn); @@ -2224,6 +2229,20 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) } old_msg = res->msgs[0]; + if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) { + struct auth_session_info *session_info = + (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); + if (security_session_user_level(session_info) != SECURITY_SYSTEM) { + ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s", + ldb_dn_get_linearized(old_msg->dn)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + /* it is already deleted - really remove it this time */ + talloc_free(tmp_ctx); + return ldb_next_request(module, req); + } + /* work out where we will be renaming this object to */ ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn); if (ret != LDB_SUCCESS) { -- cgit From 9819d280d69e5870d61a177923912eae0c573709 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 20:04:17 +1100 Subject: s4-dsdb: added dsdb_tombstone_lifetime() --- source4/dsdb/common/util.c | 26 +++++++++++++++++ source4/dsdb/kcc/kcc_deleted.c | 64 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 source4/dsdb/kcc/kcc_deleted.c (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 25d915d0bc..ea216ec67b 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -3024,3 +3024,29 @@ int dsdb_get_deleted_objects_dn(struct ldb_context *ldb, talloc_free(nc_root); return ret; } + +/* + return the tombstoneLifetime, in days + */ +int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime) +{ + struct ldb_dn *dn; + dn = samdb_config_dn(ldb); + if (!dn) { + return LDB_ERR_NO_SUCH_OBJECT; + } + dn = ldb_dn_copy(ldb, dn); + if (!dn) { + return LDB_ERR_OPERATIONS_ERROR; + } + /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to + be a wellknown GUID for this */ + if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT")) { + talloc_free(dn); + return LDB_ERR_OPERATIONS_ERROR; + } + + *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService"); + talloc_free(dn); + return LDB_SUCCESS; +} diff --git a/source4/dsdb/kcc/kcc_deleted.c b/source4/dsdb/kcc/kcc_deleted.c new file mode 100644 index 0000000000..44f3070261 --- /dev/null +++ b/source4/dsdb/kcc/kcc_deleted.c @@ -0,0 +1,64 @@ +/* + Unix SMB/CIFS implementation. + + handle removal of deleted objects + + Copyright (C) 2009 Andrew Tridgell + + 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 3 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, see . + +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "dsdb/samdb/samdb.h" +#include "auth/auth.h" +#include "smbd/service.h" +#include "lib/messaging/irpc.h" +#include "dsdb/kcc/kcc_connection.h" +#include "dsdb/kcc/kcc_service.h" +#include "lib/ldb/include/ldb_errors.h" +#include "../lib/util/dlinklist.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" +#include "param/param.h" + + +/* + check to see if any deleted objects need scavenging + */ +NTSTATUS kccsrv_check_deleted(struct kccsrv_service *s, TALLOC_CTX *mem_ctx) +{ + struct kccsrv_partition *part; + int ret; + + time_t t = time(NULL); + if (t - s->last_deleted_check < lp_parm_int(task->lp_ctx, NULL, "kccsrv", + "check_deleted_interval", 600)) { + return NT_STATUS_OK; + } + s->last_deleted_check = t; + + for (part=s->partitions; part; part=part->next) { + struct ldb_dn *do_dn; + struct ldb_result *res; + + ret = dsdb_get_deleted_objects_dn(s->samdb, mem_ctx, part->dn, &do_dn); + ret = ldb_search(s->samdb, mem_ctx, &res, do_dn, LDB_SCOPE_SUBTREE, + attrs, "isDeleted=TRUE"); + } + + +} -- cgit From 8eaed073a7c60986ecd02c3cc4beb53bd66772c6 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 20:05:02 +1100 Subject: s4-dsdb: make sure 'whenChanged' is set on modify We also should preserve (and then replace) whenChanged on delete --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index ab412942e9..202b74e8b4 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1939,6 +1939,9 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } + ldb_msg_remove_attr(msg, "whenChanged"); + ldb_msg_remove_attr(msg, "uSNChanged"); + ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(ac); @@ -2205,7 +2208,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName", "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection", "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated", - NULL}; + "whenChanged", NULL}; uint32_t el_count = 0; int i; -- cgit From 335af02218fbee7b02cbd1e4e6b40acff288465f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 21:36:31 +1100 Subject: s4-ldb: fixed valgrind error: ares can be freed by callback --- source4/lib/ldb/common/ldb_modules.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/common/ldb_modules.c b/source4/lib/ldb/common/ldb_modules.c index 5e9d0e6e98..3b8934702a 100644 --- a/source4/lib/ldb/common/ldb_modules.c +++ b/source4/lib/ldb/common/ldb_modules.c @@ -829,10 +829,7 @@ int ldb_module_done(struct ldb_request *req, ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE); } - req->callback(req, ares); - /* returning ares->error here allows the callback routines in - modules to override the error code */ - return ares->error; + return req->callback(req, ares); } /* to be used *only* in modules init functions. -- cgit From 031460b8a228ced18381ca35379aa4ea02a3f764 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 21:38:21 +1100 Subject: s4-dsdb: fixed samdb_create_foreign_security_principal() to use the wellknown GUID This also fixes a memory leak --- source4/dsdb/common/util.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index ea216ec67b..35f5c80f06 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2061,7 +2061,7 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA { struct ldb_message *msg; struct ldb_dn *basedn; - const char *sidstr; + char *sidstr; int ret; sidstr = dom_sid_string(mem_ctx, sid); @@ -2070,45 +2070,47 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA /* We might have to create a ForeignSecurityPrincipal, even if this user * is in our own domain */ - msg = ldb_msg_new(mem_ctx); + msg = ldb_msg_new(sidstr); if (msg == NULL) { + talloc_free(sidstr); return NT_STATUS_NO_MEMORY; } - /* TODO: Hmmm. This feels wrong. How do I find the base dn to - * put the ForeignSecurityPrincipals? d_state->domain_dn does - * not work, this is wrong for the Builtin domain, there's no - * cn=For...,cn=Builtin,dc={BASEDN}. -- vl - */ - - basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL, - "(&(objectClass=container)(cn=ForeignSecurityPrincipals))"); - - if (basedn == NULL) { + ret = dsdb_wellknown_dn(sam_ctx, sidstr, samdb_base_dn(sam_ctx), + DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER, + &basedn); + if (ret != LDB_SUCCESS) { DEBUG(0, ("Failed to find DN for " - "ForeignSecurityPrincipal container\n")); + "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx))); + talloc_free(sidstr); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* add core elements to the ldb_message for the alias */ - msg->dn = ldb_dn_copy(mem_ctx, basedn); - if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) + msg->dn = basedn; + if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) { + talloc_free(sidstr); return NT_STATUS_NO_MEMORY; + } - samdb_msg_add_string(sam_ctx, mem_ctx, msg, + samdb_msg_add_string(sam_ctx, msg, msg, "objectClass", "foreignSecurityPrincipal"); /* create the alias */ ret = ldb_add(sam_ctx, msg); - if (ret != 0) { + if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to create foreignSecurityPrincipal " "record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(sam_ctx))); + talloc_free(sidstr); return NT_STATUS_INTERNAL_DB_CORRUPTION; } - *ret_dn = msg->dn; + + *ret_dn = talloc_steal(mem_ctx, msg->dn); + talloc_free(sidstr); + return NT_STATUS_OK; } -- cgit From 08bad380351e9753adc4330beb06dd2929113cfc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 21:39:24 +1100 Subject: s4-dsdb: fixed several memory leaks need to be careful with those temporary contexts --- source4/dsdb/common/util.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 35f5c80f06..5d9ec1182f 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2149,14 +2149,16 @@ struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_c if (!ldb_dn_validate(dn)) { DEBUG(2, ("Failed to validated DN %s\n", ldb_dn_get_linearized(dn))); + talloc_free(tmp_ctx); return NULL; } + talloc_free(tmp_ctx); return dn; } + /* Find the DN of a domain, be it the netbios or DNS name */ - struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *domain_name) { @@ -2228,13 +2230,14 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, return LDB_ERR_OPERATIONS_ERROR; } - res = talloc_zero(mem_ctx, struct ldb_result); + res = talloc_zero(expression, struct ldb_result); if (!res) { DEBUG(0, (__location__ ": out of memory\n")); + talloc_free(expression); return LDB_ERR_OPERATIONS_ERROR; } - ret = ldb_build_search_req(&search_req, ldb, mem_ctx, + ret = ldb_build_search_req(&search_req, ldb, expression, ldb_get_default_basedn(ldb), LDB_SCOPE_SUBTREE, expression, attrs, @@ -2242,6 +2245,7 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, res, ldb_search_default_callback, NULL); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } @@ -2250,12 +2254,14 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, options = talloc(search_req, struct ldb_search_options_control); if (options == NULL) { DEBUG(0, (__location__ ": out of memory\n")); + talloc_free(expression); return LDB_ERR_OPERATIONS_ERROR; } options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT; ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } @@ -2263,16 +2269,19 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, LDB_CONTROL_SEARCH_OPTIONS_OID, true, options); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } ret = ldb_request(ldb, search_req); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } ret = ldb_wait(search_req->handle, LDB_WAIT_ALL); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } @@ -2280,10 +2289,12 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, partitions module that can return two here with the search_options control set */ if (res->count < 1) { + talloc_free(expression); return LDB_ERR_NO_SUCH_OBJECT; } - *dn = res->msgs[0]->dn; + *dn = talloc_steal(mem_ctx, res->msgs[0]->dn); + talloc_free(expression); return LDB_SUCCESS; } @@ -2306,6 +2317,7 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb, res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { + talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } @@ -2325,6 +2337,7 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb, ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL); if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); return ret; } @@ -2333,8 +2346,8 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb, ret = ldb_wait(req->handle, LDB_WAIT_ALL); } - talloc_free(req); *_res = talloc_steal(mem_ctx, res); + talloc_free(tmp_ctx); return ret; } -- cgit From cced56736431094db14d07cfe04fd7606541c339 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 21:40:17 +1100 Subject: s4-kcc: added a preiodic task to remove deleted objects we check for deleted objects in each partition every 10 minutes, using onelevel searches --- source4/dsdb/config.mk | 1 + source4/dsdb/kcc/kcc_deleted.c | 100 ++++++++++++++++++++++++++++++++++++++-- source4/dsdb/kcc/kcc_periodic.c | 5 ++ source4/dsdb/kcc/kcc_service.h | 2 + 4 files changed, 104 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index c5d1c24e04..35a0c84903 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -83,6 +83,7 @@ PRIVATE_DEPENDENCIES = \ KCC_SRV_OBJ_FILES = $(addprefix $(dsdbsrcdir)/kcc/, \ kcc_service.o \ kcc_connection.o \ + kcc_deleted.o \ kcc_periodic.o) $(eval $(call proto_header_template,$(dsdbsrcdir)/kcc/kcc_service_proto.h,$(KCC_SRV_OBJ_FILES:.o=.c))) diff --git a/source4/dsdb/kcc/kcc_deleted.c b/source4/dsdb/kcc/kcc_deleted.c index 44f3070261..d19ac0cac2 100644 --- a/source4/dsdb/kcc/kcc_deleted.c +++ b/source4/dsdb/kcc/kcc_deleted.c @@ -35,6 +35,56 @@ #include "librpc/gen_ndr/ndr_drsblobs.h" #include "param/param.h" +/* + onelevel search with SHOW_DELETED control + */ +static int search_onelevel_with_deleted(struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + struct ldb_result **_res, + struct ldb_dn *basedn, + const char * const *attrs) +{ + struct ldb_request *req; + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + int ret; + + tmp_ctx = talloc_new(mem_ctx); + + res = talloc_zero(tmp_ctx, struct ldb_result); + if (!res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&req, ldb, tmp_ctx, + basedn, + LDB_SCOPE_ONELEVEL, + NULL, + attrs, + NULL, + res, + ldb_search_default_callback, + NULL); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = ldb_request(ldb, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + *_res = talloc_steal(mem_ctx, res); + return ret; +} /* check to see if any deleted objects need scavenging @@ -43,22 +93,64 @@ NTSTATUS kccsrv_check_deleted(struct kccsrv_service *s, TALLOC_CTX *mem_ctx) { struct kccsrv_partition *part; int ret; + uint32_t tombstoneLifetime; time_t t = time(NULL); - if (t - s->last_deleted_check < lp_parm_int(task->lp_ctx, NULL, "kccsrv", + if (t - s->last_deleted_check < lp_parm_int(s->task->lp_ctx, NULL, "kccsrv", "check_deleted_interval", 600)) { return NT_STATUS_OK; } s->last_deleted_check = t; + ret = dsdb_tombstone_lifetime(s->samdb, &tombstoneLifetime); + if (ret != LDB_SUCCESS) { + DEBUG(1,(__location__ ": Failed to get tombstone lifetime\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + for (part=s->partitions; part; part=part->next) { struct ldb_dn *do_dn; struct ldb_result *res; + const char *attrs[] = { "whenChanged", NULL }; + int i; ret = dsdb_get_deleted_objects_dn(s->samdb, mem_ctx, part->dn, &do_dn); - ret = ldb_search(s->samdb, mem_ctx, &res, do_dn, LDB_SCOPE_SUBTREE, - attrs, "isDeleted=TRUE"); - } + if (ret != LDB_SUCCESS) { + /* some partitions have no Deleted Objects + container */ + continue; + } + ret = search_onelevel_with_deleted(s->samdb, do_dn, &res, do_dn, attrs); + + if (ret != LDB_SUCCESS) { + DEBUG(1,(__location__ ": Failed to search for deleted objects in %s\n", + ldb_dn_get_linearized(do_dn))); + talloc_free(do_dn); + continue; + } + + for (i=0; icount; i++) { + const char *tstring; + time_t whenChanged = 0; + tstring = samdb_result_string(res->msgs[i], "whenChanged", NULL); + if (tstring) { + whenChanged = ldb_string_to_time(tstring); + } + if (t - whenChanged > tombstoneLifetime*60*60*24) { + ret = ldb_delete(s->samdb, res->msgs[i]->dn); + if (ret != LDB_SUCCESS) { + DEBUG(1,(__location__ ": Failed to remove deleted object %s\n", + ldb_dn_get_linearized(res->msgs[i]->dn))); + } else { + DEBUG(4,("Removed deleted object %s\n", + ldb_dn_get_linearized(res->msgs[i]->dn))); + } + } + } + + talloc_free(do_dn); + } + return NT_STATUS_OK; } diff --git a/source4/dsdb/kcc/kcc_periodic.c b/source4/dsdb/kcc/kcc_periodic.c index d24e5e90a5..3b0d8a0551 100644 --- a/source4/dsdb/kcc/kcc_periodic.c +++ b/source4/dsdb/kcc/kcc_periodic.c @@ -257,5 +257,10 @@ static void kccsrv_periodic_run(struct kccsrv_service *service) if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("kccsrv_simple_update failed - %s\n", nt_errstr(status))); } + + status = kccsrv_check_deleted(service, mem_ctx); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("kccsrv_check_deleted failed - %s\n", nt_errstr(status))); + } talloc_free(mem_ctx); } diff --git a/source4/dsdb/kcc/kcc_service.h b/source4/dsdb/kcc/kcc_service.h index 6a78d37a91..b4ce37bfc5 100644 --- a/source4/dsdb/kcc/kcc_service.h +++ b/source4/dsdb/kcc/kcc_service.h @@ -78,6 +78,8 @@ struct kccsrv_service { /* here we have a reference to the timed event the schedules the periodic stuff */ struct tevent_timer *te; } periodic; + + time_t last_deleted_check; }; #include "dsdb/kcc/kcc_service_proto.h" -- cgit From 00b39c70f57882a453a8d2e6b0f1f37fd39a2d2a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 2 Jan 2010 08:14:52 +1100 Subject: s4-dsdb: switched to using RMD_FLAGS instead of DELETED in extended DNs This allows for more flags in the future --- source4/dsdb/common/dsdb_dn.h | 5 ++ source4/dsdb/common/util.c | 48 +++++++++++++++--- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 66 +++++++++++++------------ source4/lib/ldb-samba/ldif_handlers.c | 2 +- source4/rpc_server/drsuapi/getncchanges.c | 2 +- 5 files changed, 83 insertions(+), 40 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/common/dsdb_dn.h b/source4/dsdb/common/dsdb_dn.h index 53e10535c8..b713bdd27b 100644 --- a/source4/dsdb/common/dsdb_dn.h +++ b/source4/dsdb/common/dsdb_dn.h @@ -15,3 +15,8 @@ struct dsdb_dn { #define DSDB_SYNTAX_BINARY_DN "1.2.840.113556.1.4.903" #define DSDB_SYNTAX_STRING_DN "1.2.840.113556.1.4.904" #define DSDB_SYNTAX_OR_NAME "1.2.840.113556.1.4.1221" + + +/* RMD_FLAGS component in a DN */ +#define DSDB_RMD_FLAG_DELETED 1 +#define DSDB_RMD_FLAG_INVISIBLE 2 diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 5d9ec1182f..b8ba26a4ec 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2894,18 +2894,52 @@ NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const cha return NT_STATUS_OK; } +/* + return RMD_FLAGS directly from a ldb_dn + returns 0 if not found + */ +uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn) +{ + const struct ldb_val *v; + char buf[32]; + v = ldb_dn_get_extended_component(dn, "RMD_FLAGS"); + if (!v || v->length > sizeof(buf)-1) return 0; + strncpy(buf, (const char *)v->data, v->length); + buf[v->length] = 0; + return strtoul(buf, NULL, 10); +} + +/* + return RMD_FLAGS directly from a ldb_val for a DN + returns 0 if RMD_FLAGS is not found + */ +uint32_t dsdb_dn_val_rmd_flags(struct ldb_val *val) +{ + const char *p; + uint32_t flags; + char *end; + + if (val->length < 13) { + return 0; + } + p = memmem(val->data, val->length-2, " */ + return 0; + } + return flags; +} + /* return true if a ldb_val containing a DN in storage form is deleted */ bool dsdb_dn_is_deleted_val(struct ldb_val *val) { - /* this relies on the sort order and exact format of - linearized extended DNs */ - if (val->length >= 12 && - strncmp((const char *)val->data, ";", 12) == 0) { - return true; - } - return false; + return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0; } /* diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 202b74e8b4..890eb91d6d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1204,7 +1204,7 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, /* build a new extended DN, including all meta data fields - DELETED = 1 or missing + RMD_FLAGS = DSDB_RMD_FLAG_* bits RMD_ADDTIME = originating_add_time RMD_INVOCID = originating_invocation_id RMD_CHANGETIME = originating_change_time @@ -1217,15 +1217,16 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; - const char *tstring, *usn_string; + const char *tstring, *usn_string, *flags_string; struct ldb_val tval; struct ldb_val iid; struct ldb_val usnv, local_usnv; - struct ldb_val vers; + struct ldb_val vers, flagsv; NTSTATUS status; int ret; const char *dnstring; char *vstring; + uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0; tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { @@ -1246,6 +1247,9 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds local_usnv = data_blob_string_const(usn_string); vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version); + if (!vstring) { + return LDB_ERR_OPERATIONS_ERROR; + } vers = data_blob_string_const(vstring); status = GUID_to_ndr_blob(invocation_id, dn, &iid); @@ -1253,13 +1257,13 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds return LDB_ERR_OPERATIONS_ERROR; } - if (deleted) { - struct ldb_val dv; - dv = data_blob_string_const("1"); - ret = ldb_dn_set_extended_component(dn, "DELETED", &dv); - } else { - ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags); + if (!flags_string) { + return LDB_ERR_OPERATIONS_ERROR; } + flagsv = data_blob_string_const(flags_string); + + ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv); if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval); if (ret != LDB_SUCCESS) return ret; @@ -1325,17 +1329,18 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d uint32_t version, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; - const char *tstring, *usn_string; + const char *tstring, *usn_string, *flags_string; struct ldb_val tval; struct ldb_val iid; struct ldb_val usnv, local_usnv; - struct ldb_val vers; + struct ldb_val vers, flagsv; const struct ldb_val *old_addtime; uint32_t old_version; NTSTATUS status; int ret; const char *dnstring; char *vstring; + uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0; tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { @@ -1360,13 +1365,13 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d return LDB_ERR_OPERATIONS_ERROR; } - if (deleted) { - struct ldb_val dv; - dv = data_blob_string_const("1"); - ret = ldb_dn_set_extended_component(dn, "DELETED", &dv); - } else { - ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags); + if (!flags_string) { + return LDB_ERR_OPERATIONS_ERROR; } + flagsv = data_blob_string_const(flags_string); + + ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv); if (ret != LDB_SUCCESS) return ret; /* get the ADDTIME from the original */ @@ -1484,9 +1489,9 @@ static int replmd_modify_la_add(struct ldb_module *module, } else { /* this is only allowed if the GUID was previously deleted. */ - const struct ldb_val *v; - v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); - if (v == NULL) { + uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn); + + if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) { ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s", el->name, GUID_string(tmp_ctx, p->guid)); talloc_free(tmp_ctx); @@ -1595,7 +1600,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, for (i=0; inum_values; i++) { struct parsed_dn *p = &dns[i]; struct parsed_dn *p2; - const struct ldb_val *v; + uint32_t rmd_flags; p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL); if (!p2) { @@ -1603,8 +1608,8 @@ static int replmd_modify_la_delete(struct ldb_module *module, el->name, GUID_string(tmp_ctx, p->guid)); return LDB_ERR_NO_SUCH_ATTRIBUTE; } - v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED"); - if (v) { + rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn); + if (rmd_flags & DSDB_RMD_FLAG_DELETED) { ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s", el->name, GUID_string(tmp_ctx, p->guid)); return LDB_ERR_NO_SUCH_ATTRIBUTE; @@ -1616,14 +1621,14 @@ static int replmd_modify_la_delete(struct ldb_module *module, */ for (i=0; inum_values; i++) { struct parsed_dn *p = &old_dns[i]; - const struct ldb_val *v; + uint32_t rmd_flags; if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) { continue; } - v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); - if (v != NULL) continue; + rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn); + if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue; ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn, invocation_id, seq_num, seq_num, now, 0, true); @@ -1710,10 +1715,9 @@ static int replmd_modify_la_replace(struct ldb_module *module, for (i=0; idsdb_dn->dn); - v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); - if (v) continue; + if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue; ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false); if (ret != LDB_SUCCESS) { @@ -3519,7 +3523,7 @@ linked_attributes[0]: struct GUID invocation_id = GUID_zero(); uint32_t version = 0; NTTIME change_time = 0; - bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL; + uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn); dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID"); dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION"); @@ -3545,7 +3549,7 @@ linked_attributes[0]: return ret; } - if (was_active) { + if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) { /* remove the existing backlink */ ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false); if (ret != LDB_SUCCESS) { diff --git a/source4/lib/ldb-samba/ldif_handlers.c b/source4/lib/ldb-samba/ldif_handlers.c index 7ddc8e57a7..4611eba3f1 100644 --- a/source4/lib/ldb-samba/ldif_handlers.c +++ b/source4/lib/ldb-samba/ldif_handlers.c @@ -870,7 +870,7 @@ static const struct ldb_dn_extended_syntax samba_dn_syntax[] = { .write_clear_fn = ldif_write_objectGUID, .write_hex_fn = extended_dn_write_hex },{ - .name = "DELETED", + .name = "RMD_FLAGS", .read_fn = ldb_handler_copy, .write_clear_fn = ldb_handler_copy, .write_hex_fn = ldb_handler_copy diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index a41d116b6a..437dc87ae8 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -256,7 +256,7 @@ static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx, la->identifier = get_object_identifier(*la_list, msg); W_ERROR_HAVE_NO_MEMORY(la->identifier); - active = ldb_dn_get_extended_component(dsdb_dn->dn, "DELETED")?false:true; + active = (dsdb_dn_rmd_flags(dsdb_dn->dn) & DSDB_RMD_FLAG_DELETED) == 0; la->attid = sa->attributeID_id; la->flags = active?DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:0; -- cgit From a214ebc3d6c93242837ac2a4a8ccaf36c814b119 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 2 Jan 2010 02:40:30 +0100 Subject: ldb: Fix the standalone ldb build. --- source4/lib/ldb/ldb.mk | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'source4') diff --git a/source4/lib/ldb/ldb.mk b/source4/lib/ldb/ldb.mk index e87db64574..0c9b115672 100644 --- a/source4/lib/ldb/ldb.mk +++ b/source4/lib/ldb/ldb.mk @@ -34,26 +34,26 @@ lib/libldb.a: $(OBJS) sample.$(SHLIBEXT): tests/sample_module.o $(MDLD) $(MDLD_FLAGS) -o $@ tests/sample_module.o -bin/ldbadd: tools/ldbadd.o tools/cmdline.o - $(CC) -o bin/ldbadd tools/ldbadd.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) +bin/ldbadd: tools/ldbadd.o tools/cmdline.o tools/ldbutil.o + $(CC) -o bin/ldbadd tools/ldbadd.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) -bin/ldbsearch: tools/ldbsearch.o tools/cmdline.o - $(CC) -o bin/ldbsearch tools/ldbsearch.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) +bin/ldbsearch: tools/ldbsearch.o tools/cmdline.o tools/ldbutil.o + $(CC) -o bin/ldbsearch tools/ldbsearch.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) -bin/ldbdel: tools/ldbdel.o tools/cmdline.o - $(CC) -o bin/ldbdel tools/ldbdel.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) +bin/ldbdel: tools/ldbdel.o tools/cmdline.o tools/ldbutil.o + $(CC) -o bin/ldbdel tools/ldbdel.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) -bin/ldbmodify: tools/ldbmodify.o tools/cmdline.o - $(CC) -o bin/ldbmodify tools/ldbmodify.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) +bin/ldbmodify: tools/ldbmodify.o tools/cmdline.o tools/ldbutil.o + $(CC) -o bin/ldbmodify tools/ldbmodify.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) -bin/ldbedit: tools/ldbedit.o tools/cmdline.o - $(CC) -o bin/ldbedit tools/ldbedit.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) +bin/ldbedit: tools/ldbedit.o tools/cmdline.o tools/ldbutil.o + $(CC) -o bin/ldbedit tools/ldbedit.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) -bin/ldbrename: tools/ldbrename.o tools/cmdline.o - $(CC) -o bin/ldbrename tools/ldbrename.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) +bin/ldbrename: tools/ldbrename.o tools/cmdline.o tools/ldbutil.o + $(CC) -o bin/ldbrename tools/ldbrename.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) -bin/ldbtest: tools/ldbtest.o tools/cmdline.o - $(CC) -o bin/ldbtest tools/ldbtest.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) +bin/ldbtest: tools/ldbtest.o tools/cmdline.o + $(CC) -o bin/ldbtest tools/ldbtest.o tools/cmdline.o tools/ldbutil.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) examples/ldbreader: examples/ldbreader.o $(CC) -o examples/ldbreader examples/ldbreader.o $(LIB_FLAGS) -- cgit From 0bc902ac841ec883fb5a22b1db185d86ae12b114 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 2 Jan 2010 12:30:48 +1100 Subject: s4-sddl: DRS replication needs REVISION_ADS for SDs DRS replication with w2k8-r2 fails with a schema mismatch error if we set the revision to NT4 --- source4/libcli/security/sddl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/libcli/security/sddl.c b/source4/libcli/security/sddl.c index 2244a3d3ed..c4f8c5667b 100644 --- a/source4/libcli/security/sddl.c +++ b/source4/libcli/security/sddl.c @@ -304,7 +304,7 @@ static struct security_acl *sddl_decode_acl(struct security_descriptor *sd, acl = talloc_zero(sd, struct security_acl); if (acl == NULL) return NULL; - acl->revision = SECURITY_ACL_REVISION_NT4; + acl->revision = SECURITY_ACL_REVISION_ADS; if (isupper(sddl[0]) && sddl[1] == ':') { /* its an empty ACL */ -- cgit From e809b721e9d1a750c3c1bf48882532714af69e5f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 2 Jan 2010 16:51:30 +1100 Subject: s4-drs: don't give an error on repsTo delete if add is also specified w2k8-r2 in dcpromo asks for a delete+add during its initial join. --- source4/rpc_server/drsuapi/updaterefs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/rpc_server/drsuapi/updaterefs.c b/source4/rpc_server/drsuapi/updaterefs.c index 6e2efed4f9..b1e3d6c352 100644 --- a/source4/rpc_server/drsuapi/updaterefs.c +++ b/source4/rpc_server/drsuapi/updaterefs.c @@ -105,7 +105,9 @@ static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, return werr; } - if (!found && !(options & DRSUAPI_DS_REPLICA_UPDATE_GETCHG_CHECK)) { + if (!found && + !(options & DRSUAPI_DS_REPLICA_UPDATE_GETCHG_CHECK) && + !(options & DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE)) { return WERR_DS_DRA_REF_NOT_FOUND; } -- cgit From 504754856eed363dde28cdff821c086754deb7f8 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 2 Jan 2010 16:53:20 +1100 Subject: s4-dsdb: force REVISION_ADS for new and updated ACLs in dsdb w2k8-r2 gives a "schema mismatch" error if the revision is not set to REVISION_ADS and you replicate the ntsecuritydescriptor using DRS. Nadya, please check this! Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/descriptor.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/descriptor.c b/source4/dsdb/samdb/ldb_modules/descriptor.c index d5a5e36e0e..f07743c4a2 100644 --- a/source4/dsdb/samdb/ldb_modules/descriptor.c +++ b/source4/dsdb/samdb/ldb_modules/descriptor.c @@ -285,6 +285,14 @@ static DATA_BLOB *get_new_descriptor(struct ldb_module *module, if (!final_sd) { return NULL; } + + if (final_sd->dacl) { + final_sd->dacl->revision = SECURITY_ACL_REVISION_ADS; + } + if (final_sd->sacl) { + final_sd->sacl->revision = SECURITY_ACL_REVISION_ADS; + } + sddl_sd = sddl_encode(mem_ctx, final_sd, domain_sid); DEBUG(10, ("Object %s created with desriptor %s\n\n", ldb_dn_get_linearized(dn), sddl_sd)); -- cgit From a06e5cdb99ddf7abf16486d3837105ec4e0da9ee Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 4 Jan 2010 08:42:49 +0100 Subject: s4: Happy New Year 2010 metze --- source4/smbd/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/smbd/server.c b/source4/smbd/server.c index ddfa220a72..e73cdfd659 100644 --- a/source4/smbd/server.c +++ b/source4/smbd/server.c @@ -326,7 +326,7 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[ umask(0); DEBUG(0,("%s version %s started.\n", binary_name, SAMBA_VERSION_STRING)); - DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2009\n")); + DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2010\n")); if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) { DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); -- cgit