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