1/* 2 Unix SMB/CIFS implementation. 3 4 implement the DRSUpdateRefs call 5 6 Copyright (C) Andrew Tridgell 2009 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "rpc_server/dcerpc_server.h" 24#include "dsdb/samdb/samdb.h" 25#include "auth/auth.h" 26#include "rpc_server/drsuapi/dcesrv_drsuapi.h" 27#include "libcli/security/security.h" 28 29struct repsTo { 30 uint32_t count; 31 struct repsFromToBlob *r; 32}; 33 34/* 35 add a replication destination for a given partition GUID 36 */ 37static WERROR uref_add_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 38 struct ldb_dn *dn, struct repsFromTo1 *dest) 39{ 40 struct repsTo reps; 41 WERROR werr; 42 43 werr = dsdb_loadreps(sam_ctx, mem_ctx, dn, "repsTo", &reps.r, &reps.count); 44 if (!W_ERROR_IS_OK(werr)) { 45 return werr; 46 } 47 48 reps.r = talloc_realloc(mem_ctx, reps.r, struct repsFromToBlob, reps.count+1); 49 if (reps.r == NULL) { 50 return WERR_DS_DRA_INTERNAL_ERROR; 51 } 52 ZERO_STRUCT(reps.r[reps.count]); 53 reps.r[reps.count].version = 1; 54 reps.r[reps.count].ctr.ctr1 = *dest; 55 reps.count++; 56 57 werr = dsdb_savereps(sam_ctx, mem_ctx, dn, "repsTo", reps.r, reps.count); 58 if (!W_ERROR_IS_OK(werr)) { 59 return werr; 60 } 61 62 return WERR_OK; 63} 64 65/* 66 delete a replication destination for a given partition GUID 67 */ 68static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 69 struct ldb_dn *dn, struct GUID *dest_guid) 70{ 71 struct repsTo reps; 72 WERROR werr; 73 int i; 74 75 werr = dsdb_loadreps(sam_ctx, mem_ctx, dn, "repsTo", &reps.r, &reps.count); 76 if (!W_ERROR_IS_OK(werr)) { 77 return werr; 78 } 79 80 for (i=0; i<reps.count; i++) { 81 if (GUID_compare(dest_guid, &reps.r[i].ctr.ctr1.source_dsa_obj_guid) == 0) { 82 if (i+1 < reps.count) { 83 memmove(&reps.r[i], &reps.r[i+1], sizeof(reps.r[i])*(reps.count-(i+1))); 84 } 85 reps.count--; 86 } 87 } 88 89 werr = dsdb_savereps(sam_ctx, mem_ctx, dn, "repsTo", reps.r, reps.count); 90 if (!W_ERROR_IS_OK(werr)) { 91 return werr; 92 } 93 94 return WERR_OK; 95} 96 97/* 98 drsuapi_DsReplicaUpdateRefs 99*/ 100WERROR dcesrv_drsuapi_DsReplicaUpdateRefs(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 101 struct drsuapi_DsReplicaUpdateRefs *r) 102{ 103 struct drsuapi_DsReplicaUpdateRefsRequest1 *req; 104 struct ldb_context *sam_ctx; 105 WERROR werr; 106 struct ldb_dn *dn; 107 108 werr = drs_security_level_check(dce_call, "DsReplicaUpdateRefs"); 109 if (!W_ERROR_IS_OK(werr)) { 110 return werr; 111 } 112 113 if (r->in.level != 1) { 114 DEBUG(0,("DrReplicUpdateRefs - unsupported level %u\n", r->in.level)); 115 return WERR_DS_DRA_INVALID_PARAMETER; 116 } 117 118 req = &r->in.req.req1; 119 DEBUG(4,("DsReplicaUpdateRefs for host '%s' with GUID %s options 0x%08x nc=%s\n", 120 req->dest_dsa_dns_name, GUID_string(mem_ctx, &req->dest_dsa_guid), 121 req->options, 122 drs_ObjectIdentifier_to_string(mem_ctx, req->naming_context))); 123 124 /* TODO: We need to authenticate this operation pretty carefully */ 125 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, 126 system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx)); 127 if (!sam_ctx) { 128 return WERR_DS_DRA_INTERNAL_ERROR; 129 } 130 131 dn = ldb_dn_new(mem_ctx, sam_ctx, req->naming_context->dn); 132 if (dn == NULL) { 133 talloc_free(sam_ctx); 134 return WERR_DS_INVALID_DN_SYNTAX; 135 } 136 137 if (ldb_transaction_start(sam_ctx) != LDB_SUCCESS) { 138 DEBUG(0,(__location__ ": Failed to start transaction on samdb\n")); 139 talloc_free(sam_ctx); 140 return WERR_DS_DRA_INTERNAL_ERROR; 141 } 142 143 if (req->options & DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE) { 144 werr = uref_del_dest(sam_ctx, mem_ctx, dn, &req->dest_dsa_guid); 145 if (!W_ERROR_IS_OK(werr)) { 146 DEBUG(0,("Failed to delete repsTo for %s\n", 147 GUID_string(dce_call, &req->dest_dsa_guid))); 148 goto failed; 149 } 150 } 151 152 if (req->options & DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE) { 153 struct repsFromTo1 dest; 154 struct repsFromTo1OtherInfo oi; 155 156 ZERO_STRUCT(dest); 157 ZERO_STRUCT(oi); 158 159 oi.dns_name = req->dest_dsa_dns_name; 160 dest.other_info = &oi; 161 dest.source_dsa_obj_guid = req->dest_dsa_guid; 162 dest.replica_flags = req->options; 163 164 werr = uref_add_dest(sam_ctx, mem_ctx, dn, &dest); 165 if (!W_ERROR_IS_OK(werr)) { 166 DEBUG(0,("Failed to delete repsTo for %s\n", 167 GUID_string(dce_call, &dest.source_dsa_obj_guid))); 168 goto failed; 169 } 170 } 171 172 if (ldb_transaction_commit(sam_ctx) != LDB_SUCCESS) { 173 DEBUG(0,(__location__ ": Failed to commit transaction on samdb\n")); 174 return WERR_DS_DRA_INTERNAL_ERROR; 175 } 176 177 talloc_free(sam_ctx); 178 return WERR_OK; 179 180failed: 181 ldb_transaction_cancel(sam_ctx); 182 talloc_free(sam_ctx); 183 return werr; 184} 185