1/* 2 Unix SMB/CIFS mplementation. 3 4 KCC service 5 6 Copyright (C) Andrew Tridgell 2009 7 based on repl service code 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21 22*/ 23 24#include "includes.h" 25#include "dsdb/samdb/samdb.h" 26#include "auth/auth.h" 27#include "smbd/service.h" 28#include "lib/events/events.h" 29#include "lib/messaging/irpc.h" 30#include "dsdb/kcc/kcc_service.h" 31#include "lib/ldb/include/ldb_errors.h" 32#include "../lib/util/dlinklist.h" 33#include "librpc/gen_ndr/ndr_misc.h" 34#include "librpc/gen_ndr/ndr_drsuapi.h" 35#include "librpc/gen_ndr/ndr_drsblobs.h" 36#include "param/param.h" 37 38/* 39 establish system creds 40 */ 41static WERROR kccsrv_init_creds(struct kccsrv_service *service) 42{ 43 NTSTATUS status; 44 45 status = auth_system_session_info(service, service->task->lp_ctx, 46 &service->system_session_info); 47 if (!NT_STATUS_IS_OK(status)) { 48 return ntstatus_to_werror(status); 49 } 50 51 return WERR_OK; 52} 53 54/* 55 connect to the local SAM 56 */ 57static WERROR kccsrv_connect_samdb(struct kccsrv_service *service, struct loadparm_context *lp_ctx) 58{ 59 const struct GUID *ntds_guid; 60 61 service->samdb = samdb_connect(service, service->task->event_ctx, lp_ctx, service->system_session_info); 62 if (!service->samdb) { 63 return WERR_DS_UNAVAILABLE; 64 } 65 66 ntds_guid = samdb_ntds_objectGUID(service->samdb); 67 if (!ntds_guid) { 68 return WERR_DS_UNAVAILABLE; 69 } 70 71 service->ntds_guid = *ntds_guid; 72 73 return WERR_OK; 74} 75 76 77/* 78 load our local partition list 79 */ 80static WERROR kccsrv_load_partitions(struct kccsrv_service *s) 81{ 82 struct ldb_dn *basedn; 83 struct ldb_result *r; 84 struct ldb_message_element *el; 85 static const char *attrs[] = { "namingContexts", "configurationNamingContext", NULL }; 86 uint32_t i; 87 int ret; 88 89 basedn = ldb_dn_new(s, s->samdb, NULL); 90 W_ERROR_HAVE_NO_MEMORY(basedn); 91 92 ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs, 93 "(objectClass=*)"); 94 talloc_free(basedn); 95 if (ret != LDB_SUCCESS) { 96 return WERR_FOOBAR; 97 } else if (r->count != 1) { 98 talloc_free(r); 99 return WERR_FOOBAR; 100 } 101 102 el = ldb_msg_find_element(r->msgs[0], "namingContexts"); 103 if (!el) { 104 return WERR_FOOBAR; 105 } 106 107 for (i=0; el && i < el->num_values; i++) { 108 const char *v = (const char *)el->values[i].data; 109 struct ldb_dn *pdn; 110 struct kccsrv_partition *p; 111 112 pdn = ldb_dn_new(s, s->samdb, v); 113 if (!ldb_dn_validate(pdn)) { 114 return WERR_FOOBAR; 115 } 116 117 p = talloc_zero(s, struct kccsrv_partition); 118 W_ERROR_HAVE_NO_MEMORY(p); 119 120 p->dn = talloc_steal(p, pdn); 121 p->service = s; 122 123 DLIST_ADD(s->partitions, p); 124 125 DEBUG(2, ("kccsrv_partition[%s] loaded\n", v)); 126 } 127 128 el = ldb_msg_find_element(r->msgs[0], "configurationNamingContext"); 129 if (!el) { 130 return WERR_FOOBAR; 131 } 132 s->config_dn = ldb_dn_new(s, s->samdb, (const char *)el->values[0].data); 133 if (!ldb_dn_validate(s->config_dn)) { 134 return WERR_FOOBAR; 135 } 136 137 talloc_free(r); 138 139 return WERR_OK; 140} 141 142 143/* 144 startup the kcc service task 145*/ 146static void kccsrv_task_init(struct task_server *task) 147{ 148 WERROR status; 149 struct kccsrv_service *service; 150 uint32_t periodic_startup_interval; 151 152 switch (lp_server_role(task->lp_ctx)) { 153 case ROLE_STANDALONE: 154 task_server_terminate(task, "kccsrv: no KCC required in standalone configuration", false); 155 return; 156 case ROLE_DOMAIN_MEMBER: 157 task_server_terminate(task, "kccsrv: no KCC required in domain member configuration", false); 158 return; 159 case ROLE_DOMAIN_CONTROLLER: 160 /* Yes, we want a KCC */ 161 break; 162 } 163 164 task_server_set_title(task, "task[kccsrv]"); 165 166 service = talloc_zero(task, struct kccsrv_service); 167 if (!service) { 168 task_server_terminate(task, "kccsrv_task_init: out of memory", true); 169 return; 170 } 171 service->task = task; 172 service->startup_time = timeval_current(); 173 task->private_data = service; 174 175 status = kccsrv_init_creds(service); 176 if (!W_ERROR_IS_OK(status)) { 177 task_server_terminate(task, 178 talloc_asprintf(task, 179 "kccsrv: Failed to obtain server credentials: %s\n", 180 win_errstr(status)), true); 181 return; 182 } 183 184 status = kccsrv_connect_samdb(service, task->lp_ctx); 185 if (!W_ERROR_IS_OK(status)) { 186 task_server_terminate(task, talloc_asprintf(task, 187 "kccsrv: Failed to connect to local samdb: %s\n", 188 win_errstr(status)), true); 189 return; 190 } 191 192 status = kccsrv_load_partitions(service); 193 if (!W_ERROR_IS_OK(status)) { 194 task_server_terminate(task, talloc_asprintf(task, 195 "kccsrv: Failed to load partitions: %s\n", 196 win_errstr(status)), true); 197 return; 198 } 199 200 periodic_startup_interval = lp_parm_int(task->lp_ctx, NULL, "kccsrv", 201 "periodic_startup_interval", 15); /* in seconds */ 202 service->periodic.interval = lp_parm_int(task->lp_ctx, NULL, "kccsrv", 203 "periodic_interval", 300); /* in seconds */ 204 205 status = kccsrv_periodic_schedule(service, periodic_startup_interval); 206 if (!W_ERROR_IS_OK(status)) { 207 task_server_terminate(task, talloc_asprintf(task, 208 "kccsrv: Failed to periodic schedule: %s\n", 209 win_errstr(status)), true); 210 return; 211 } 212 213 irpc_add_name(task->msg_ctx, "kccsrv"); 214} 215 216/* 217 register ourselves as a available server 218*/ 219NTSTATUS server_service_kcc_init(void) 220{ 221 return register_server_service("kcc", kccsrv_task_init); 222} 223