1/* 2 Unix SMB/CIFS implementation. 3 4 Copyright (C) Brad Henry 2005 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include "libnet/libnet.h" 22#include "libcli/cldap/cldap.h" 23#include "lib/ldb/include/ldb.h" 24#include "lib/ldb/include/ldb_errors.h" 25#include "librpc/rpc/dcerpc.h" 26#include "libcli/resolve/resolve.h" 27#include "param/param.h" 28 29/** 30 * 1. Setup a CLDAP socket. 31 * 2. Lookup the default Site-Name. 32 */ 33NTSTATUS libnet_FindSite(TALLOC_CTX *ctx, struct libnet_context *lctx, struct libnet_JoinSite *r) 34{ 35 NTSTATUS status; 36 TALLOC_CTX *tmp_ctx; 37 38 char *site_name_str; 39 char *config_dn_str; 40 char *server_dn_str; 41 42 struct cldap_socket *cldap = NULL; 43 struct cldap_netlogon search; 44 45 tmp_ctx = talloc_named(ctx, 0, "libnet_FindSite temp context"); 46 if (!tmp_ctx) { 47 r->out.error_string = NULL; 48 return NT_STATUS_NO_MEMORY; 49 } 50 51 /* Resolve the site name. */ 52 ZERO_STRUCT(search); 53 search.in.dest_address = r->in.dest_address; 54 search.in.dest_port = r->in.cldap_port; 55 search.in.acct_control = -1; 56 search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; 57 search.in.map_response = true; 58 59 /* we want to use non async calls, so we're not passing an event context */ 60 status = cldap_socket_init(tmp_ctx, NULL, NULL, NULL, &cldap);//TODO 61 if (!NT_STATUS_IS_OK(status)) { 62 talloc_free(tmp_ctx); 63 r->out.error_string = NULL; 64 return status; 65 } 66 status = cldap_netlogon(cldap, lp_iconv_convenience(lctx->lp_ctx), tmp_ctx, &search); 67 if (!NT_STATUS_IS_OK(status) 68 || !search.out.netlogon.data.nt5_ex.client_site) { 69 /* 70 If cldap_netlogon() returns in error, 71 default to using Default-First-Site-Name. 72 */ 73 site_name_str = talloc_asprintf(tmp_ctx, "%s", 74 "Default-First-Site-Name"); 75 if (!site_name_str) { 76 r->out.error_string = NULL; 77 talloc_free(tmp_ctx); 78 return NT_STATUS_NO_MEMORY; 79 } 80 } else { 81 site_name_str = talloc_asprintf(tmp_ctx, "%s", 82 search.out.netlogon.data.nt5_ex.client_site); 83 if (!site_name_str) { 84 r->out.error_string = NULL; 85 talloc_free(tmp_ctx); 86 return NT_STATUS_NO_MEMORY; 87 } 88 } 89 90 /* Generate the CN=Configuration,... DN. */ 91/* TODO: look it up! */ 92 config_dn_str = talloc_asprintf(tmp_ctx, "CN=Configuration,%s", r->in.domain_dn_str); 93 if (!config_dn_str) { 94 r->out.error_string = NULL; 95 talloc_free(tmp_ctx); 96 return NT_STATUS_NO_MEMORY; 97 } 98 99 /* Generate the CN=Servers,... DN. */ 100 server_dn_str = talloc_asprintf(tmp_ctx, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s", 101 r->in.netbios_name, site_name_str, config_dn_str); 102 if (!server_dn_str) { 103 r->out.error_string = NULL; 104 talloc_free(tmp_ctx); 105 return NT_STATUS_NO_MEMORY; 106 } 107 108 r->out.site_name_str = site_name_str; 109 talloc_steal(r, site_name_str); 110 111 r->out.config_dn_str = config_dn_str; 112 talloc_steal(r, config_dn_str); 113 114 r->out.server_dn_str = server_dn_str; 115 talloc_steal(r, server_dn_str); 116 117 talloc_free(tmp_ctx); 118 return NT_STATUS_OK; 119} 120 121/* 122 * find out Site specific stuff: 123 * 1. Lookup the Site name. 124 * 2. Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>. 125 * TODO: 3.) use DsAddEntry() to create CN=NTDS Settings,CN=<netbios name>,CN=Servers,CN=<site name>,... 126 */ 127NTSTATUS libnet_JoinSite(struct libnet_context *ctx, 128 struct ldb_context *remote_ldb, 129 struct libnet_JoinDomain *libnet_r) 130{ 131 NTSTATUS status; 132 TALLOC_CTX *tmp_ctx; 133 134 struct libnet_JoinSite *r; 135 136 struct ldb_dn *server_dn; 137 struct ldb_message *msg; 138 int rtn; 139 140 const char *server_dn_str; 141 const char *config_dn_str; 142 struct nbt_name name; 143 const char *dest_addr = NULL; 144 145 tmp_ctx = talloc_named(libnet_r, 0, "libnet_JoinSite temp context"); 146 if (!tmp_ctx) { 147 libnet_r->out.error_string = NULL; 148 return NT_STATUS_NO_MEMORY; 149 } 150 151 r = talloc(tmp_ctx, struct libnet_JoinSite); 152 if (!r) { 153 libnet_r->out.error_string = NULL; 154 talloc_free(tmp_ctx); 155 return NT_STATUS_NO_MEMORY; 156 } 157 158 make_nbt_name_client(&name, libnet_r->out.samr_binding->host); 159 status = resolve_name(lp_resolve_context(ctx->lp_ctx), &name, r, &dest_addr, ctx->event_ctx); 160 if (!NT_STATUS_IS_OK(status)) { 161 libnet_r->out.error_string = NULL; 162 talloc_free(tmp_ctx); 163 return status; 164 } 165 166 /* Resolve the site name and AD DN's. */ 167 r->in.dest_address = dest_addr; 168 r->in.netbios_name = libnet_r->in.netbios_name; 169 r->in.domain_dn_str = libnet_r->out.domain_dn_str; 170 r->in.cldap_port = lp_cldap_port(ctx->lp_ctx); 171 172 status = libnet_FindSite(tmp_ctx, ctx, r); 173 if (!NT_STATUS_IS_OK(status)) { 174 libnet_r->out.error_string = 175 talloc_steal(libnet_r, r->out.error_string); 176 talloc_free(tmp_ctx); 177 return status; 178 } 179 180 config_dn_str = r->out.config_dn_str; 181 server_dn_str = r->out.server_dn_str; 182 183 /* 184 Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>. 185 */ 186 msg = ldb_msg_new(tmp_ctx); 187 if (!msg) { 188 libnet_r->out.error_string = NULL; 189 talloc_free(tmp_ctx); 190 return NT_STATUS_NO_MEMORY; 191 } 192 193 rtn = ldb_msg_add_string(msg, "objectClass", "server"); 194 if (rtn != 0) { 195 libnet_r->out.error_string = NULL; 196 talloc_free(tmp_ctx); 197 return NT_STATUS_NO_MEMORY; 198 } 199 rtn = ldb_msg_add_string(msg, "systemFlags", "50000000"); 200 if (rtn != 0) { 201 libnet_r->out.error_string = NULL; 202 talloc_free(tmp_ctx); 203 return NT_STATUS_NO_MEMORY; 204 } 205 rtn = ldb_msg_add_string(msg, "serverReference", libnet_r->out.account_dn_str); 206 if (rtn != 0) { 207 libnet_r->out.error_string = NULL; 208 talloc_free(tmp_ctx); 209 return NT_STATUS_NO_MEMORY; 210 } 211 212 server_dn = ldb_dn_new(tmp_ctx, remote_ldb, server_dn_str); 213 if ( ! ldb_dn_validate(server_dn)) { 214 libnet_r->out.error_string = talloc_asprintf(libnet_r, 215 "Invalid server dn: %s", 216 server_dn_str); 217 talloc_free(tmp_ctx); 218 return NT_STATUS_UNSUCCESSFUL; 219 } 220 221 msg->dn = server_dn; 222 223 rtn = ldb_add(remote_ldb, msg); 224 if (rtn == LDB_ERR_ENTRY_ALREADY_EXISTS) { 225 int i; 226 227 /* make a 'modify' msg, and only for serverReference */ 228 msg = ldb_msg_new(tmp_ctx); 229 if (!msg) { 230 libnet_r->out.error_string = NULL; 231 talloc_free(tmp_ctx); 232 return NT_STATUS_NO_MEMORY; 233 } 234 msg->dn = server_dn; 235 236 rtn = ldb_msg_add_string(msg, "serverReference",libnet_r->out.account_dn_str); 237 if (rtn != 0) { 238 libnet_r->out.error_string = NULL; 239 talloc_free(tmp_ctx); 240 return NT_STATUS_NO_MEMORY; 241 } 242 243 /* mark all the message elements (should be just one) 244 as LDB_FLAG_MOD_REPLACE */ 245 for (i=0;i<msg->num_elements;i++) { 246 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; 247 } 248 249 rtn = ldb_modify(remote_ldb, msg); 250 if (rtn != 0) { 251 libnet_r->out.error_string 252 = talloc_asprintf(libnet_r, 253 "Failed to modify server entry %s: %s: %d", 254 server_dn_str, 255 ldb_errstring(remote_ldb), rtn); 256 talloc_free(tmp_ctx); 257 return NT_STATUS_INTERNAL_DB_CORRUPTION; 258 } 259 } else if (rtn != 0) { 260 libnet_r->out.error_string 261 = talloc_asprintf(libnet_r, 262 "Failed to add server entry %s: %s: %d", 263 server_dn_str, ldb_errstring(remote_ldb), 264 rtn); 265 talloc_free(tmp_ctx); 266 return NT_STATUS_INTERNAL_DB_CORRUPTION; 267 } 268 DEBUG(0, ("We still need to perform a DsAddEntry() so that we can create the CN=NTDS Settings container.\n")); 269 270 /* Store the server DN in libnet_r */ 271 libnet_r->out.server_dn_str = server_dn_str; 272 talloc_steal(libnet_r, server_dn_str); 273 274 talloc_free(tmp_ctx); 275 return NT_STATUS_OK; 276} 277