s4-repl: use common functions to simplify updaterefs.c
[kamenim/samba.git] / source4 / rpc_server / drsuapi / updaterefs.c
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 "librpc/gen_ndr/ndr_drsuapi.h"
24 #include "rpc_server/dcerpc_server.h"
25 #include "rpc_server/common/common.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "lib/ldb/include/ldb_errors.h"
28 #include "param/param.h"
29 #include "librpc/gen_ndr/ndr_drsblobs.h"
30 #include "auth/auth.h"
31 #include "rpc_server/drsuapi/dcesrv_drsuapi.h"
32
33 struct repsTo {
34         uint32_t count;
35         struct repsFromToBlob *r;
36 };
37
38 /*
39   add a replication destination for a given partition GUID
40  */
41 static WERROR uref_add_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
42                             struct ldb_dn *dn, struct repsFromTo1 *dest)
43 {
44         struct repsTo reps;
45         WERROR werr;
46
47         werr = dsdb_loadreps(sam_ctx, mem_ctx, dn, "repsTo", &reps.r, &reps.count);
48         if (!W_ERROR_IS_OK(werr)) {
49                 return werr;
50         }
51
52         reps.r = talloc_realloc(mem_ctx, reps.r, struct repsFromToBlob, reps.count+1);
53         if (reps.r == NULL) {
54                 return WERR_DS_DRA_INTERNAL_ERROR;
55         }
56         ZERO_STRUCT(reps.r[reps.count]);
57         reps.r[reps.count].version = 1;
58         reps.r[reps.count].ctr.ctr1 = *dest;
59         reps.count++;
60
61         werr = dsdb_savereps(sam_ctx, mem_ctx, dn, "repsTo", reps.r, reps.count);
62         if (!W_ERROR_IS_OK(werr)) {
63                 return werr;
64         }
65
66         return WERR_OK; 
67 }
68
69 /*
70   delete a replication destination for a given partition GUID
71  */
72 static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
73                             struct ldb_dn *dn, struct GUID *dest_guid)
74 {
75         struct repsTo reps;
76         WERROR werr;
77         int i;
78
79         werr = dsdb_loadreps(sam_ctx, mem_ctx, dn, "repsTo", &reps.r, &reps.count);
80         if (!W_ERROR_IS_OK(werr)) {
81                 return werr;
82         }
83
84         for (i=0; i<reps.count; i++) {
85                 if (GUID_compare(dest_guid, &reps.r[i].ctr.ctr1.source_dsa_obj_guid) == 0) {
86                         if (i+1 < reps.count) {
87                                 memmove(&reps.r[i], &reps.r[i+1], sizeof(reps.r[i])*(reps.count-(i+1)));
88                         }
89                         reps.count--;
90                 }
91         }
92
93         werr = dsdb_savereps(sam_ctx, mem_ctx, dn, "repsTo", reps.r, reps.count);
94         if (!W_ERROR_IS_OK(werr)) {
95                 return werr;
96         }
97
98         return WERR_OK; 
99 }
100
101 /* 
102   drsuapi_DsReplicaUpdateRefs
103 */
104 WERROR dcesrv_drsuapi_DsReplicaUpdateRefs(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
105                                           struct drsuapi_DsReplicaUpdateRefs *r)
106 {
107         struct drsuapi_DsReplicaUpdateRefsRequest1 *req;
108         struct ldb_context *sam_ctx;
109         WERROR werr;
110         struct ldb_dn *dn;
111
112         if (r->in.level != 1) {
113                 DEBUG(0,("DrReplicUpdateRefs - unsupported level %u\n", r->in.level));
114                 return WERR_DS_DRA_INVALID_PARAMETER;
115         }
116
117         req = &r->in.req.req1;
118         DEBUG(4,("DsReplicaUpdateRefs for host '%s' with GUID %s options 0x%08x nc=%s\n",
119                  req->dest_dsa_dns_name, GUID_string(mem_ctx, &req->dest_dsa_guid),
120                  req->options,
121                  drs_ObjectIdentifier_to_string(mem_ctx, req->naming_context)));
122
123         /* TODO: We need to authenticate this operation pretty carefully */
124         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, 
125                                 system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
126         if (!sam_ctx) {
127                 return WERR_DS_DRA_INTERNAL_ERROR;              
128         }
129
130         dn = ldb_dn_new(mem_ctx, sam_ctx, req->naming_context->dn);
131         if (dn == NULL) {
132                 talloc_free(sam_ctx);           
133                 return WERR_DS_INVALID_DN_SYNTAX;
134         }
135
136         if (ldb_transaction_start(sam_ctx) != LDB_SUCCESS) {
137                 DEBUG(0,(__location__ ": Failed to start transaction on samdb\n"));
138                 talloc_free(sam_ctx);
139                 return WERR_DS_DRA_INTERNAL_ERROR;              
140         }
141
142         if (req->options & DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE) {
143                 werr = uref_del_dest(sam_ctx, mem_ctx, dn, &req->dest_dsa_guid);
144                 if (!W_ERROR_IS_OK(werr)) {
145                         DEBUG(0,("Failed to delete repsTo for %s\n",
146                                  GUID_string(dce_call, &req->dest_dsa_guid)));
147                         goto failed;
148                 }
149         }
150
151         if (req->options & DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE) {
152                 struct repsFromTo1 dest;
153                 struct repsFromTo1OtherInfo oi;
154                 
155                 ZERO_STRUCT(dest);
156                 ZERO_STRUCT(oi);
157
158                 oi.dns_name = req->dest_dsa_dns_name;
159                 dest.other_info          = &oi;
160                 dest.source_dsa_obj_guid = req->dest_dsa_guid;
161                 dest.replica_flags       = req->options;
162
163                 werr = uref_add_dest(sam_ctx, mem_ctx, dn, &dest);
164                 if (!W_ERROR_IS_OK(werr)) {
165                         DEBUG(0,("Failed to delete repsTo for %s\n",
166                                  GUID_string(dce_call, &dest.source_dsa_obj_guid)));
167                         goto failed;
168                 }
169         }
170
171         if (ldb_transaction_commit(sam_ctx) != LDB_SUCCESS) {
172                 DEBUG(0,(__location__ ": Failed to commit transaction on samdb\n"));
173                 return WERR_DS_DRA_INTERNAL_ERROR;              
174         }
175
176         talloc_free(sam_ctx);
177         return WERR_OK;
178
179 failed:
180         ldb_transaction_cancel(sam_ctx);
181         talloc_free(sam_ctx);
182         return werr;
183 }