1/* 2 Unix SMB/CIFS mplementation. 3 DSDB replication service 4 5 Copyright (C) Stefan Metzmacher 2007 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19 20*/ 21 22#include "includes.h" 23#include "dsdb/samdb/samdb.h" 24#include "auth/auth.h" 25#include "smbd/service.h" 26#include "lib/events/events.h" 27#include "lib/messaging/irpc.h" 28#include "dsdb/repl/drepl_service.h" 29#include "lib/ldb/include/ldb_errors.h" 30#include "../lib/util/dlinklist.h" 31#include "librpc/gen_ndr/ndr_misc.h" 32#include "librpc/gen_ndr/ndr_drsuapi.h" 33#include "librpc/gen_ndr/ndr_drsblobs.h" 34#include "param/param.h" 35 36WERROR dreplsrv_load_partitions(struct dreplsrv_service *s) 37{ 38 WERROR status; 39 struct ldb_dn *basedn; 40 struct ldb_result *r; 41 struct ldb_message_element *el; 42 static const char *attrs[] = { "namingContexts", NULL }; 43 uint32_t i; 44 int ret; 45 46 basedn = ldb_dn_new(s, s->samdb, NULL); 47 W_ERROR_HAVE_NO_MEMORY(basedn); 48 49 ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs, 50 "(objectClass=*)"); 51 talloc_free(basedn); 52 if (ret != LDB_SUCCESS) { 53 return WERR_FOOBAR; 54 } else if (r->count != 1) { 55 talloc_free(r); 56 return WERR_FOOBAR; 57 } 58 59 el = ldb_msg_find_element(r->msgs[0], "namingContexts"); 60 if (!el) { 61 return WERR_FOOBAR; 62 } 63 64 for (i=0; el && i < el->num_values; i++) { 65 const char *v = (const char *)el->values[i].data; 66 struct ldb_dn *pdn; 67 struct dreplsrv_partition *p; 68 69 pdn = ldb_dn_new(s, s->samdb, v); 70 if (!ldb_dn_validate(pdn)) { 71 return WERR_FOOBAR; 72 } 73 74 p = talloc_zero(s, struct dreplsrv_partition); 75 W_ERROR_HAVE_NO_MEMORY(p); 76 77 p->dn = talloc_steal(p, pdn); 78 79 DLIST_ADD(s->partitions, p); 80 81 DEBUG(2, ("dreplsrv_partition[%s] loaded\n", v)); 82 } 83 84 talloc_free(r); 85 86 status = dreplsrv_refresh_partitions(s); 87 W_ERROR_NOT_OK_RETURN(status); 88 89 return WERR_OK; 90} 91 92static WERROR dreplsrv_out_connection_attach(struct dreplsrv_service *s, 93 const struct repsFromTo1 *rft, 94 struct dreplsrv_out_connection **_conn) 95{ 96 struct dreplsrv_out_connection *cur, *conn = NULL; 97 const char *hostname; 98 99 if (!rft->other_info) { 100 return WERR_FOOBAR; 101 } 102 103 if (!rft->other_info->dns_name) { 104 return WERR_FOOBAR; 105 } 106 107 hostname = rft->other_info->dns_name; 108 109 for (cur = s->connections; cur; cur = cur->next) { 110 if (strcmp(cur->binding->host, hostname) == 0) { 111 conn = cur; 112 break; 113 } 114 } 115 116 if (!conn) { 117 NTSTATUS nt_status; 118 char *binding_str; 119 120 conn = talloc_zero(s, struct dreplsrv_out_connection); 121 W_ERROR_HAVE_NO_MEMORY(conn); 122 123 conn->service = s; 124 125 binding_str = talloc_asprintf(conn, "ncacn_ip_tcp:%s[krb5,seal]", 126 hostname); 127 W_ERROR_HAVE_NO_MEMORY(binding_str); 128 nt_status = dcerpc_parse_binding(conn, binding_str, &conn->binding); 129 talloc_free(binding_str); 130 if (!NT_STATUS_IS_OK(nt_status)) { 131 return ntstatus_to_werror(nt_status); 132 } 133 134 DLIST_ADD_END(s->connections, conn, struct dreplsrv_out_connection *); 135 136 DEBUG(2,("dreplsrv_out_connection_attach(%s): create\n", conn->binding->host)); 137 } else { 138 DEBUG(2,("dreplsrv_out_connection_attach(%s): attach\n", conn->binding->host)); 139 } 140 141 *_conn = conn; 142 return WERR_OK; 143} 144 145static WERROR dreplsrv_partition_add_source_dsa(struct dreplsrv_service *s, 146 struct dreplsrv_partition *p, 147 const struct ldb_val *val) 148{ 149 WERROR status; 150 enum ndr_err_code ndr_err; 151 struct dreplsrv_partition_source_dsa *source, *s2; 152 153 source = talloc_zero(p, struct dreplsrv_partition_source_dsa); 154 W_ERROR_HAVE_NO_MEMORY(source); 155 156 ndr_err = ndr_pull_struct_blob(val, source, 157 lp_iconv_convenience(s->task->lp_ctx), &source->_repsFromBlob, 158 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob); 159 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 160 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err); 161 talloc_free(source); 162 return ntstatus_to_werror(nt_status); 163 } 164 /* NDR_PRINT_DEBUG(repsFromToBlob, &source->_repsFromBlob); */ 165 if (source->_repsFromBlob.version != 1) { 166 talloc_free(source); 167 return WERR_DS_DRA_INTERNAL_ERROR; 168 } 169 170 source->partition = p; 171 source->repsFrom1 = &source->_repsFromBlob.ctr.ctr1; 172 173 status = dreplsrv_out_connection_attach(s, source->repsFrom1, &source->conn); 174 W_ERROR_NOT_OK_RETURN(status); 175 176 /* remove any existing source with the same GUID */ 177 for (s2=p->sources; s2; s2=s2->next) { 178 if (GUID_compare(&s2->repsFrom1->source_dsa_obj_guid, 179 &source->repsFrom1->source_dsa_obj_guid) == 0) { 180 talloc_free(s2->repsFrom1->other_info); 181 *s2->repsFrom1 = *source->repsFrom1; 182 talloc_steal(s2, s2->repsFrom1->other_info); 183 talloc_free(source); 184 return WERR_OK; 185 } 186 } 187 188 DLIST_ADD_END(p->sources, source, struct dreplsrv_partition_source_dsa *); 189 return WERR_OK; 190} 191 192static WERROR dreplsrv_refresh_partition(struct dreplsrv_service *s, 193 struct dreplsrv_partition *p) 194{ 195 WERROR status; 196 const struct ldb_val *ouv_value; 197 struct replUpToDateVectorBlob ouv; 198 struct dom_sid *nc_sid; 199 struct ldb_message_element *orf_el = NULL; 200 struct ldb_result *r; 201 uint32_t i; 202 int ret; 203 TALLOC_CTX *mem_ctx = talloc_new(p); 204 static const char *attrs[] = { 205 "objectSid", 206 "objectGUID", 207 "replUpToDateVector", 208 "repsFrom", 209 NULL 210 }; 211 212 DEBUG(2, ("dreplsrv_refresh_partition(%s)\n", 213 ldb_dn_get_linearized(p->dn))); 214 215 ret = ldb_search(s->samdb, mem_ctx, &r, p->dn, LDB_SCOPE_BASE, attrs, 216 "(objectClass=*)"); 217 if (ret != LDB_SUCCESS) { 218 talloc_free(mem_ctx); 219 return WERR_FOOBAR; 220 } else if (r->count != 1) { 221 talloc_free(mem_ctx); 222 return WERR_FOOBAR; 223 } 224 225 talloc_free(discard_const(p->nc.dn)); 226 ZERO_STRUCT(p->nc); 227 p->nc.dn = ldb_dn_alloc_linearized(p, p->dn); 228 W_ERROR_HAVE_NO_MEMORY(p->nc.dn); 229 p->nc.guid = samdb_result_guid(r->msgs[0], "objectGUID"); 230 nc_sid = samdb_result_dom_sid(p, r->msgs[0], "objectSid"); 231 if (nc_sid) { 232 p->nc.sid = *nc_sid; 233 talloc_free(nc_sid); 234 } 235 236 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector"); 237 if (ouv_value) { 238 enum ndr_err_code ndr_err; 239 ndr_err = ndr_pull_struct_blob(ouv_value, mem_ctx, 240 lp_iconv_convenience(s->task->lp_ctx), &ouv, 241 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob); 242 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 243 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err); 244 talloc_free(mem_ctx); 245 return ntstatus_to_werror(nt_status); 246 } 247 /* NDR_PRINT_DEBUG(replUpToDateVectorBlob, &ouv); */ 248 if (ouv.version != 2) { 249 talloc_free(mem_ctx); 250 return WERR_DS_DRA_INTERNAL_ERROR; 251 } 252 253 p->uptodatevector.count = ouv.ctr.ctr2.count; 254 p->uptodatevector.reserved = ouv.ctr.ctr2.reserved; 255 talloc_free(p->uptodatevector.cursors); 256 p->uptodatevector.cursors = talloc_steal(p, ouv.ctr.ctr2.cursors); 257 } 258 259 /* 260 * TODO: add our own uptodatevector cursor 261 */ 262 263 264 orf_el = ldb_msg_find_element(r->msgs[0], "repsFrom"); 265 if (orf_el) { 266 for (i=0; i < orf_el->num_values; i++) { 267 status = dreplsrv_partition_add_source_dsa(s, p, &orf_el->values[i]); 268 W_ERROR_NOT_OK_RETURN(status); 269 } 270 } 271 272 talloc_free(mem_ctx); 273 274 return WERR_OK; 275} 276 277WERROR dreplsrv_refresh_partitions(struct dreplsrv_service *s) 278{ 279 WERROR status; 280 struct dreplsrv_partition *p; 281 282 for (p = s->partitions; p; p = p->next) { 283 status = dreplsrv_refresh_partition(s, p); 284 W_ERROR_NOT_OK_RETURN(status); 285 } 286 287 return WERR_OK; 288} 289