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