s4-drs-fsmo: try to dispatch ops in queue as soon as possible
[abartlet/samba.git/.git] / source4 / dsdb / repl / drepl_fsmo.c
1 /*
2    Unix SMB/CIFS mplementation.
3
4    DSDB replication service - FSMO role change
5
6    Copyright (C) Nadezhda Ivanova 2010
7    Copyright (C) Andrew Tridgell 2010
8    Copyright (C) Andrew Bartlett 2010
9
10    based on drepl_ridalloc.c
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
25 */
26
27 #include "includes.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "smbd/service.h"
30 #include "dsdb/repl/drepl_service.h"
31 #include "param/param.h"
32 #include "lib/messaging/irpc.h"
33 #include "librpc/gen_ndr/ndr_irpc.h"
34
35 static void drepl_role_callback(struct dreplsrv_service *service,
36                                 WERROR werr,
37                                 enum drsuapi_DsExtendedError ext_err)
38 {
39         if (!W_ERROR_IS_OK(werr)) {
40                 DEBUG(0,(__location__ ": Failed role transfer - %s - extended_ret[0x%X]\n",
41                          win_errstr(werr), ext_err));
42         } else {
43                 DEBUG(0,(__location__ ": Successful role transfer\n"));
44         }
45         talloc_free(service->ncchanges_extended.role_owner_source_dsa);
46         service->ncchanges_extended.role_owner_source_dsa = NULL;
47         service->ncchanges_extended.in_progress = false;
48 }
49
50 static bool fsmo_master_cmp(struct ldb_dn *ntds_dn, struct ldb_dn *fsmo_role_dn)
51 {
52         if (ldb_dn_compare(ntds_dn, fsmo_role_dn) == 0) {
53                 DEBUG(0,("\nWe are the FSMO master.\n"));
54                 return true;
55         }
56         return false;
57 }
58
59 /*
60   see which role is we are asked to assume, initialize data and send request
61  */
62 WERROR dreplsrv_fsmo_role_check(struct dreplsrv_service *service,
63                                 uint32_t role)
64 {
65         struct ldb_dn *role_owner_dn, *fsmo_role_dn, *ntds_dn;
66         TALLOC_CTX *tmp_ctx = talloc_new(service);
67         struct ldb_context *ldb = service->samdb;
68         int ret;
69         uint64_t alloc_pool = 0;
70
71         if (service->ncchanges_extended.in_progress) {
72                 talloc_free(tmp_ctx);
73                 return WERR_OK;
74         }
75
76         ntds_dn = samdb_ntds_settings_dn(ldb);
77         if (!ntds_dn) {
78                 return WERR_DS_DRA_INTERNAL_ERROR;
79         }
80         /* work out who is the current owner */
81         switch (role) {
82         case DREPL_NAMING_MASTER:
83                 role_owner_dn = samdb_partitions_dn(ldb, tmp_ctx),
84                 ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
85                 if (ret != LDB_SUCCESS) {
86                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
87                                  ldb_errstring(ldb)));
88                         talloc_free(tmp_ctx);
89                         return WERR_DS_DRA_INTERNAL_ERROR;
90                 }
91                 break;
92         case DREPL_INFRASTRUCTURE_MASTER:
93                 role_owner_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
94                 ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
95                 if (ret != LDB_SUCCESS) {
96                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
97                                  ldb_errstring(ldb)));
98                         talloc_free(tmp_ctx);
99                         return WERR_DS_DRA_INTERNAL_ERROR;
100                 }
101                 break;
102         case DREPL_RID_MASTER:
103                 ret = samdb_rid_manager_dn(ldb, tmp_ctx, &role_owner_dn);
104                 if (ret != LDB_SUCCESS) {
105                         DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
106                         talloc_free(tmp_ctx);
107                         return WERR_DS_DRA_INTERNAL_ERROR;
108                 }
109
110                 /* find the DN of the RID Manager */
111                 ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
112                 if (ret != LDB_SUCCESS) {
113                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
114                                  ldb_errstring(ldb)));
115                         talloc_free(tmp_ctx);
116                         return WERR_DS_DRA_INTERNAL_ERROR;
117                 }
118                 break;
119         case DREPL_SCHEMA_MASTER:
120                 role_owner_dn = ldb_get_schema_basedn(ldb);
121                 ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
122                 if (ret != LDB_SUCCESS) {
123                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
124                                  ldb_errstring(ldb)));
125                         talloc_free(tmp_ctx);
126                         return WERR_DS_DRA_INTERNAL_ERROR;
127                 }
128                 if (!fsmo_master_cmp(ntds_dn, fsmo_role_dn)) {
129                         WERROR werr;
130                         werr = drepl_request_extended_op(service,
131                                                          role_owner_dn,
132                                                          fsmo_role_dn,
133                                                          DRSUAPI_EXOP_FSMO_REQ_ROLE,
134                                                          alloc_pool,
135                                                          drepl_role_callback);
136                         if (W_ERROR_IS_OK(werr)) {
137                                 dreplsrv_run_pending_ops(service);
138                         } else {
139                                 DEBUG(0,("%s: drepl_request_extended_op() failed with %s",
140                                                  __FUNCTION__, win_errstr(werr)));
141                         }
142                         return werr;
143                 }
144                 break;
145         case DREPL_PDC_MASTER:
146                 role_owner_dn = ldb_get_default_basedn(ldb);
147                 ret = samdb_reference_dn(ldb, tmp_ctx, role_owner_dn, "fSMORoleOwner", &fsmo_role_dn);
148                 if (ret != LDB_SUCCESS) {
149                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
150                                  ldb_errstring(ldb)));
151                         talloc_free(tmp_ctx);
152                         return WERR_DS_DRA_INTERNAL_ERROR;
153                 }
154                 break;
155         default:
156                 return WERR_DS_DRA_INTERNAL_ERROR;
157         }
158         return WERR_OK;
159 }