1/* 2 * Unix SMB/CIFS implementation. 3 * NetApi Join Support 4 * Copyright (C) Guenther Deschner 2007-2008 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 22#include "librpc/gen_ndr/libnetapi.h" 23#include "lib/netapi/netapi.h" 24#include "lib/netapi/netapi_private.h" 25#include "lib/netapi/libnetapi.h" 26#include "libnet/libnet.h" 27#include "libcli/auth/libcli_auth.h" 28#include "../librpc/gen_ndr/cli_wkssvc.h" 29 30/**************************************************************** 31****************************************************************/ 32 33WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx, 34 struct NetJoinDomain *r) 35{ 36 struct libnet_JoinCtx *j = NULL; 37 WERROR werr; 38 39 if (!r->in.domain) { 40 return WERR_INVALID_PARAM; 41 } 42 43 werr = libnet_init_JoinCtx(mem_ctx, &j); 44 W_ERROR_NOT_OK_RETURN(werr); 45 46 j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain); 47 W_ERROR_HAVE_NO_MEMORY(j->in.domain_name); 48 49 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) { 50 NTSTATUS status; 51 struct netr_DsRGetDCNameInfo *info = NULL; 52 const char *dc = NULL; 53 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED | 54 DS_WRITABLE_REQUIRED | 55 DS_RETURN_DNS_NAME; 56 status = dsgetdcname(mem_ctx, NULL, r->in.domain, 57 NULL, NULL, flags, &info); 58 if (!NT_STATUS_IS_OK(status)) { 59 libnetapi_set_error_string(mem_ctx, 60 "%s", get_friendly_nt_error_msg(status)); 61 return ntstatus_to_werror(status); 62 } 63 64 dc = strip_hostname(info->dc_unc); 65 j->in.dc_name = talloc_strdup(mem_ctx, dc); 66 W_ERROR_HAVE_NO_MEMORY(j->in.dc_name); 67 } 68 69 if (r->in.account_ou) { 70 j->in.account_ou = talloc_strdup(mem_ctx, r->in.account_ou); 71 W_ERROR_HAVE_NO_MEMORY(j->in.account_ou); 72 } 73 74 if (r->in.account) { 75 j->in.admin_account = talloc_strdup(mem_ctx, r->in.account); 76 W_ERROR_HAVE_NO_MEMORY(j->in.admin_account); 77 } 78 79 if (r->in.password) { 80 j->in.admin_password = talloc_strdup(mem_ctx, r->in.password); 81 W_ERROR_HAVE_NO_MEMORY(j->in.admin_password); 82 } 83 84 j->in.join_flags = r->in.join_flags; 85 j->in.modify_config = true; 86 j->in.debug = true; 87 88 werr = libnet_Join(mem_ctx, j); 89 if (!W_ERROR_IS_OK(werr) && j->out.error_string) { 90 libnetapi_set_error_string(mem_ctx, "%s", j->out.error_string); 91 } 92 TALLOC_FREE(j); 93 94 return werr; 95} 96 97/**************************************************************** 98****************************************************************/ 99 100WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx, 101 struct NetJoinDomain *r) 102{ 103 struct rpc_pipe_client *pipe_cli = NULL; 104 struct wkssvc_PasswordBuffer *encrypted_password = NULL; 105 NTSTATUS status; 106 WERROR werr; 107 unsigned int old_timeout = 0; 108 109 werr = libnetapi_open_pipe(ctx, r->in.server, 110 &ndr_table_wkssvc.syntax_id, 111 &pipe_cli); 112 if (!W_ERROR_IS_OK(werr)) { 113 goto done; 114 } 115 116 if (r->in.password) { 117 encode_wkssvc_join_password_buffer(ctx, 118 r->in.password, 119 &pipe_cli->auth->user_session_key, 120 &encrypted_password); 121 } 122 123 old_timeout = rpccli_set_timeout(pipe_cli, 600000); 124 125 status = rpccli_wkssvc_NetrJoinDomain2(pipe_cli, talloc_tos(), 126 r->in.server, 127 r->in.domain, 128 r->in.account_ou, 129 r->in.account, 130 encrypted_password, 131 r->in.join_flags, 132 &werr); 133 if (!NT_STATUS_IS_OK(status)) { 134 werr = ntstatus_to_werror(status); 135 goto done; 136 } 137 138 done: 139 if (pipe_cli && old_timeout) { 140 rpccli_set_timeout(pipe_cli, old_timeout); 141 } 142 143 return werr; 144} 145/**************************************************************** 146****************************************************************/ 147 148WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx, 149 struct NetUnjoinDomain *r) 150{ 151 struct libnet_UnjoinCtx *u = NULL; 152 struct dom_sid domain_sid; 153 const char *domain = NULL; 154 WERROR werr; 155 156 if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { 157 return WERR_SETUP_NOT_JOINED; 158 } 159 160 werr = libnet_init_UnjoinCtx(mem_ctx, &u); 161 W_ERROR_NOT_OK_RETURN(werr); 162 163 if (lp_realm()) { 164 domain = lp_realm(); 165 } else { 166 domain = lp_workgroup(); 167 } 168 169 if (r->in.server_name) { 170 u->in.dc_name = talloc_strdup(mem_ctx, r->in.server_name); 171 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name); 172 } else { 173 NTSTATUS status; 174 struct netr_DsRGetDCNameInfo *info = NULL; 175 const char *dc = NULL; 176 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED | 177 DS_WRITABLE_REQUIRED | 178 DS_RETURN_DNS_NAME; 179 status = dsgetdcname(mem_ctx, NULL, domain, 180 NULL, NULL, flags, &info); 181 if (!NT_STATUS_IS_OK(status)) { 182 libnetapi_set_error_string(mem_ctx, 183 "failed to find DC for domain %s: %s", 184 domain, 185 get_friendly_nt_error_msg(status)); 186 return ntstatus_to_werror(status); 187 } 188 189 dc = strip_hostname(info->dc_unc); 190 u->in.dc_name = talloc_strdup(mem_ctx, dc); 191 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name); 192 193 u->in.domain_name = domain; 194 } 195 196 if (r->in.account) { 197 u->in.admin_account = talloc_strdup(mem_ctx, r->in.account); 198 W_ERROR_HAVE_NO_MEMORY(u->in.admin_account); 199 } 200 201 if (r->in.password) { 202 u->in.admin_password = talloc_strdup(mem_ctx, r->in.password); 203 W_ERROR_HAVE_NO_MEMORY(u->in.admin_password); 204 } 205 206 u->in.domain_name = domain; 207 u->in.unjoin_flags = r->in.unjoin_flags; 208 u->in.delete_machine_account = false; 209 u->in.modify_config = true; 210 u->in.debug = true; 211 212 u->in.domain_sid = &domain_sid; 213 214 werr = libnet_Unjoin(mem_ctx, u); 215 if (!W_ERROR_IS_OK(werr) && u->out.error_string) { 216 libnetapi_set_error_string(mem_ctx, "%s", u->out.error_string); 217 } 218 TALLOC_FREE(u); 219 220 return werr; 221} 222 223/**************************************************************** 224****************************************************************/ 225 226WERROR NetUnjoinDomain_r(struct libnetapi_ctx *ctx, 227 struct NetUnjoinDomain *r) 228{ 229 struct rpc_pipe_client *pipe_cli = NULL; 230 struct wkssvc_PasswordBuffer *encrypted_password = NULL; 231 NTSTATUS status; 232 WERROR werr; 233 unsigned int old_timeout = 0; 234 235 werr = libnetapi_open_pipe(ctx, r->in.server_name, 236 &ndr_table_wkssvc.syntax_id, 237 &pipe_cli); 238 if (!W_ERROR_IS_OK(werr)) { 239 goto done; 240 } 241 242 if (r->in.password) { 243 encode_wkssvc_join_password_buffer(ctx, 244 r->in.password, 245 &pipe_cli->auth->user_session_key, 246 &encrypted_password); 247 } 248 249 old_timeout = rpccli_set_timeout(pipe_cli, 60000); 250 251 status = rpccli_wkssvc_NetrUnjoinDomain2(pipe_cli, talloc_tos(), 252 r->in.server_name, 253 r->in.account, 254 encrypted_password, 255 r->in.unjoin_flags, 256 &werr); 257 if (!NT_STATUS_IS_OK(status)) { 258 werr = ntstatus_to_werror(status); 259 goto done; 260 } 261 262 done: 263 if (pipe_cli && old_timeout) { 264 rpccli_set_timeout(pipe_cli, old_timeout); 265 } 266 267 return werr; 268} 269 270/**************************************************************** 271****************************************************************/ 272 273WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx, 274 struct NetGetJoinInformation *r) 275{ 276 struct rpc_pipe_client *pipe_cli = NULL; 277 NTSTATUS status; 278 WERROR werr; 279 const char *buffer = NULL; 280 281 werr = libnetapi_open_pipe(ctx, r->in.server_name, 282 &ndr_table_wkssvc.syntax_id, 283 &pipe_cli); 284 if (!W_ERROR_IS_OK(werr)) { 285 goto done; 286 } 287 288 status = rpccli_wkssvc_NetrGetJoinInformation(pipe_cli, talloc_tos(), 289 r->in.server_name, 290 &buffer, 291 (enum wkssvc_NetJoinStatus *)r->out.name_type, 292 &werr); 293 if (!NT_STATUS_IS_OK(status)) { 294 werr = ntstatus_to_werror(status); 295 goto done; 296 } 297 298 *r->out.name_buffer = talloc_strdup(ctx, buffer); 299 W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer); 300 301 done: 302 return werr; 303} 304 305/**************************************************************** 306****************************************************************/ 307 308WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx, 309 struct NetGetJoinInformation *r) 310{ 311 if ((lp_security() == SEC_ADS) && lp_realm()) { 312 *r->out.name_buffer = talloc_strdup(ctx, lp_realm()); 313 } else { 314 *r->out.name_buffer = talloc_strdup(ctx, lp_workgroup()); 315 } 316 if (!*r->out.name_buffer) { 317 return WERR_NOMEM; 318 } 319 320 switch (lp_server_role()) { 321 case ROLE_DOMAIN_MEMBER: 322 case ROLE_DOMAIN_PDC: 323 case ROLE_DOMAIN_BDC: 324 *r->out.name_type = NetSetupDomainName; 325 break; 326 case ROLE_STANDALONE: 327 default: 328 *r->out.name_type = NetSetupWorkgroupName; 329 break; 330 } 331 332 return WERR_OK; 333} 334 335/**************************************************************** 336****************************************************************/ 337 338WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx, 339 struct NetGetJoinableOUs *r) 340{ 341#ifdef WITH_ADS 342 NTSTATUS status; 343 ADS_STATUS ads_status; 344 ADS_STRUCT *ads = NULL; 345 struct netr_DsRGetDCNameInfo *info = NULL; 346 const char *dc = NULL; 347 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED | 348 DS_RETURN_DNS_NAME; 349 350 status = dsgetdcname(ctx, NULL, r->in.domain, 351 NULL, NULL, flags, &info); 352 if (!NT_STATUS_IS_OK(status)) { 353 libnetapi_set_error_string(ctx, "%s", 354 get_friendly_nt_error_msg(status)); 355 return ntstatus_to_werror(status); 356 } 357 358 dc = strip_hostname(info->dc_unc); 359 360 ads = ads_init(info->domain_name, info->domain_name, dc); 361 if (!ads) { 362 return WERR_GENERAL_FAILURE; 363 } 364 365 SAFE_FREE(ads->auth.user_name); 366 if (r->in.account) { 367 ads->auth.user_name = SMB_STRDUP(r->in.account); 368 } else if (ctx->username) { 369 ads->auth.user_name = SMB_STRDUP(ctx->username); 370 } 371 372 SAFE_FREE(ads->auth.password); 373 if (r->in.password) { 374 ads->auth.password = SMB_STRDUP(r->in.password); 375 } else if (ctx->password) { 376 ads->auth.password = SMB_STRDUP(ctx->password); 377 } 378 379 ads_status = ads_connect_user_creds(ads); 380 if (!ADS_ERR_OK(ads_status)) { 381 ads_destroy(&ads); 382 return WERR_DEFAULT_JOIN_REQUIRED; 383 } 384 385 ads_status = ads_get_joinable_ous(ads, ctx, 386 (char ***)r->out.ous, 387 (size_t *)r->out.ou_count); 388 if (!ADS_ERR_OK(ads_status)) { 389 ads_destroy(&ads); 390 return WERR_DEFAULT_JOIN_REQUIRED; 391 } 392 393 ads_destroy(&ads); 394 return WERR_OK; 395#else 396 return WERR_NOT_SUPPORTED; 397#endif 398} 399 400/**************************************************************** 401****************************************************************/ 402 403WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx, 404 struct NetGetJoinableOUs *r) 405{ 406 struct rpc_pipe_client *pipe_cli = NULL; 407 struct wkssvc_PasswordBuffer *encrypted_password = NULL; 408 NTSTATUS status; 409 WERROR werr; 410 411 werr = libnetapi_open_pipe(ctx, r->in.server_name, 412 &ndr_table_wkssvc.syntax_id, 413 &pipe_cli); 414 if (!W_ERROR_IS_OK(werr)) { 415 goto done; 416 } 417 418 if (r->in.password) { 419 encode_wkssvc_join_password_buffer(ctx, 420 r->in.password, 421 &pipe_cli->auth->user_session_key, 422 &encrypted_password); 423 } 424 425 status = rpccli_wkssvc_NetrGetJoinableOus2(pipe_cli, talloc_tos(), 426 r->in.server_name, 427 r->in.domain, 428 r->in.account, 429 encrypted_password, 430 r->out.ou_count, 431 r->out.ous, 432 &werr); 433 if (!NT_STATUS_IS_OK(status)) { 434 werr = ntstatus_to_werror(status); 435 goto done; 436 } 437 438 done: 439 return werr; 440} 441 442/**************************************************************** 443****************************************************************/ 444 445WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx, 446 struct NetRenameMachineInDomain *r) 447{ 448 struct rpc_pipe_client *pipe_cli = NULL; 449 struct wkssvc_PasswordBuffer *encrypted_password = NULL; 450 NTSTATUS status; 451 WERROR werr; 452 453 werr = libnetapi_open_pipe(ctx, r->in.server_name, 454 &ndr_table_wkssvc.syntax_id, 455 &pipe_cli); 456 if (!W_ERROR_IS_OK(werr)) { 457 goto done; 458 } 459 460 if (r->in.password) { 461 encode_wkssvc_join_password_buffer(ctx, 462 r->in.password, 463 &pipe_cli->auth->user_session_key, 464 &encrypted_password); 465 } 466 467 status = rpccli_wkssvc_NetrRenameMachineInDomain2(pipe_cli, talloc_tos(), 468 r->in.server_name, 469 r->in.new_machine_name, 470 r->in.account, 471 encrypted_password, 472 r->in.rename_options, 473 &werr); 474 if (!NT_STATUS_IS_OK(status)) { 475 werr = ntstatus_to_werror(status); 476 goto done; 477 } 478 479 done: 480 return werr; 481} 482 483/**************************************************************** 484****************************************************************/ 485 486WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx, 487 struct NetRenameMachineInDomain *r) 488{ 489 LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRenameMachineInDomain); 490} 491