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