Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
[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 "lib/netapi/netapi.h"
23 #include "libnet/libnet.h"
24
25 /****************************************************************
26 ****************************************************************/
27
28 static WERROR NetJoinDomainLocal(struct libnetapi_ctx *mem_ctx,
29                                  const char *server_name,
30                                  const char *domain_name,
31                                  const char *account_ou,
32                                  const char *Account,
33                                  const char *password,
34                                  uint32_t join_flags)
35 {
36         struct libnet_JoinCtx *r = NULL;
37         WERROR werr;
38
39         if (!domain_name) {
40                 return WERR_INVALID_PARAM;
41         }
42
43         werr = libnet_init_JoinCtx(mem_ctx, &r);
44         W_ERROR_NOT_OK_RETURN(werr);
45
46         r->in.domain_name = talloc_strdup(mem_ctx, domain_name);
47         W_ERROR_HAVE_NO_MEMORY(r->in.domain_name);
48
49         if (join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
50                 NTSTATUS status;
51                 struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
52                 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
53                                  DS_WRITABLE_REQUIRED |
54                                  DS_RETURN_DNS_NAME;
55                 status = dsgetdcname(mem_ctx, domain_name,
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                 r->in.dc_name = talloc_strdup(mem_ctx,
63                                               info->domain_controller_name);
64                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
65         }
66
67         if (account_ou) {
68                 r->in.account_ou = talloc_strdup(mem_ctx, account_ou);
69                 W_ERROR_HAVE_NO_MEMORY(r->in.account_ou);
70         }
71
72         if (Account) {
73                 r->in.admin_account = talloc_strdup(mem_ctx, Account);
74                 W_ERROR_HAVE_NO_MEMORY(r->in.admin_account);
75         }
76
77         if (password) {
78                 r->in.admin_password = talloc_strdup(mem_ctx, password);
79                 W_ERROR_HAVE_NO_MEMORY(r->in.admin_password);
80         }
81
82         r->in.join_flags = join_flags;
83         r->in.modify_config = true;
84
85         werr = libnet_Join(mem_ctx, r);
86         if (!W_ERROR_IS_OK(werr) && r->out.error_string) {
87                 libnetapi_set_error_string(mem_ctx, "%s", r->out.error_string);
88         }
89         TALLOC_FREE(r);
90
91         return werr;
92 }
93
94 /****************************************************************
95 ****************************************************************/
96
97 static WERROR NetJoinDomainRemote(struct libnetapi_ctx *ctx,
98                                   const char *server_name,
99                                   const char *domain_name,
100                                   const char *account_ou,
101                                   const char *Account,
102                                   const char *password,
103                                   uint32_t join_flags)
104 {
105         struct cli_state *cli = NULL;
106         struct rpc_pipe_client *pipe_cli = NULL;
107         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
108         NTSTATUS status;
109         WERROR werr;
110         unsigned int old_timeout = 0;
111
112         status = cli_full_connection(&cli, NULL, server_name,
113                                      NULL, 0,
114                                      "IPC$", "IPC",
115                                      ctx->username,
116                                      ctx->workgroup,
117                                      ctx->password,
118                                      0, Undefined, NULL);
119
120         if (!NT_STATUS_IS_OK(status)) {
121                 werr = ntstatus_to_werror(status);
122                 goto done;
123         }
124
125         pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_WKSSVC,
126                                             &status);
127         if (!pipe_cli) {
128                 werr = ntstatus_to_werror(status);
129                 goto done;
130         }
131
132         if (password) {
133                 encode_wkssvc_join_password_buffer(ctx,
134                                                    password,
135                                                    &cli->user_session_key,
136                                                    &encrypted_password);
137         }
138
139         old_timeout = cli_set_timeout(cli, 60000);
140
141         status = rpccli_wkssvc_NetrJoinDomain2(pipe_cli, ctx,
142                                                server_name, domain_name,
143                                                account_ou, Account,
144                                                encrypted_password,
145                                                join_flags, &werr);
146         if (!NT_STATUS_IS_OK(status)) {
147                 werr = ntstatus_to_werror(status);
148                 goto done;
149         }
150
151  done:
152         if (cli) {
153                 cli_set_timeout(cli, old_timeout);
154                 cli_shutdown(cli);
155         }
156
157         return werr;
158 }
159
160 /****************************************************************
161 ****************************************************************/
162
163 static WERROR libnetapi_NetJoinDomain(struct libnetapi_ctx *ctx,
164                                       const char *server_name,
165                                       const char *domain_name,
166                                       const char *account_ou,
167                                       const char *Account,
168                                       const char *password,
169                                       uint32_t join_flags)
170 {
171         if (!domain_name) {
172                 return WERR_INVALID_PARAM;
173         }
174
175         if (!server_name || is_myname_or_ipaddr(server_name)) {
176
177                 return NetJoinDomainLocal(ctx,
178                                           server_name,
179                                           domain_name,
180                                           account_ou,
181                                           Account,
182                                           password,
183                                           join_flags);
184         }
185
186         return NetJoinDomainRemote(ctx,
187                                    server_name,
188                                    domain_name,
189                                    account_ou,
190                                    Account,
191                                    password,
192                                    join_flags);
193 }
194
195 /****************************************************************
196  NetJoinDomain
197 ****************************************************************/
198
199 NET_API_STATUS NetJoinDomain(const char *server_name,
200                              const char *domain_name,
201                              const char *account_ou,
202                              const char *Account,
203                              const char *password,
204                              uint32_t join_flags)
205 {
206         struct libnetapi_ctx *ctx = NULL;
207         NET_API_STATUS status;
208         WERROR werr;
209
210         status = libnetapi_getctx(&ctx);
211         if (status != 0) {
212                 return status;
213         }
214
215         werr = libnetapi_NetJoinDomain(ctx,
216                                        server_name,
217                                        domain_name,
218                                        account_ou,
219                                        Account,
220                                        password,
221                                        join_flags);
222         if (!W_ERROR_IS_OK(werr)) {
223                 return W_ERROR_V(werr);
224         }
225
226         return NET_API_STATUS_SUCCESS;
227 }
228
229 /****************************************************************
230 ****************************************************************/
231
232 static WERROR NetUnjoinDomainLocal(struct libnetapi_ctx *mem_ctx,
233                                    const char *server_name,
234                                    const char *account,
235                                    const char *password,
236                                    uint32_t unjoin_flags)
237 {
238         struct libnet_UnjoinCtx *r = NULL;
239         struct dom_sid domain_sid;
240         WERROR werr;
241
242         if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
243                 return WERR_SETUP_NOT_JOINED;
244         }
245
246         werr = libnet_init_UnjoinCtx(mem_ctx, &r);
247         W_ERROR_NOT_OK_RETURN(werr);
248
249         if (server_name) {
250                 r->in.dc_name = talloc_strdup(mem_ctx, server_name);
251                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
252         } else {
253                 NTSTATUS status;
254                 const char *domain = NULL;
255                 struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
256                 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
257                                  DS_WRITABLE_REQUIRED |
258                                  DS_RETURN_DNS_NAME;
259                 if (lp_realm()) {
260                         domain = lp_realm();
261                 } else {
262                         domain = lp_workgroup();
263                 }
264                 status = dsgetdcname(mem_ctx, domain,
265                                      NULL, NULL, flags, &info);
266                 if (!NT_STATUS_IS_OK(status)) {
267                         libnetapi_set_error_string(mem_ctx,
268                                 "%s", get_friendly_nt_error_msg(status));
269                         return ntstatus_to_werror(status);
270                 }
271                 r->in.dc_name = talloc_strdup(mem_ctx,
272                                               info->domain_controller_name);
273                 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
274         }
275
276         if (account) {
277                 r->in.admin_account = talloc_strdup(mem_ctx, account);
278                 W_ERROR_HAVE_NO_MEMORY(r->in.admin_account);
279         }
280
281         if (password) {
282                 r->in.admin_password = talloc_strdup(mem_ctx, password);
283                 W_ERROR_HAVE_NO_MEMORY(r->in.admin_password);
284         }
285
286         r->in.unjoin_flags = unjoin_flags;
287         r->in.modify_config = true;
288         r->in.debug = true;
289
290         r->in.domain_sid = &domain_sid;
291
292         werr = libnet_Unjoin(mem_ctx, r);
293         if (!W_ERROR_IS_OK(werr) && r->out.error_string) {
294                 libnetapi_set_error_string(mem_ctx, "%s", r->out.error_string);
295         }
296         TALLOC_FREE(r);
297
298         return werr;
299 }
300
301 /****************************************************************
302 ****************************************************************/
303
304 static WERROR NetUnjoinDomainRemote(struct libnetapi_ctx *ctx,
305                                     const char *server_name,
306                                     const char *account,
307                                     const char *password,
308                                     uint32_t unjoin_flags)
309 {
310         struct cli_state *cli = NULL;
311         struct rpc_pipe_client *pipe_cli = NULL;
312         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
313         NTSTATUS status;
314         WERROR werr;
315         unsigned int old_timeout = 0;
316
317         status = cli_full_connection(&cli, NULL, server_name,
318                                      NULL, 0,
319                                      "IPC$", "IPC",
320                                      ctx->username,
321                                      ctx->workgroup,
322                                      ctx->password,
323                                      0, Undefined, NULL);
324
325         if (!NT_STATUS_IS_OK(status)) {
326                 werr = ntstatus_to_werror(status);
327                 goto done;
328         }
329
330         pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_WKSSVC,
331                                             &status);
332         if (!pipe_cli) {
333                 werr = ntstatus_to_werror(status);
334                 goto done;
335         }
336
337         if (password) {
338                 encode_wkssvc_join_password_buffer(ctx,
339                                                    password,
340                                                    &cli->user_session_key,
341                                                    &encrypted_password);
342         }
343
344         old_timeout = cli_set_timeout(cli, 60000);
345
346         status = rpccli_wkssvc_NetrUnjoinDomain2(pipe_cli, ctx,
347                                                  server_name,
348                                                  account,
349                                                  encrypted_password,
350                                                  unjoin_flags,
351                                                  &werr);
352         if (!NT_STATUS_IS_OK(status)) {
353                 werr = ntstatus_to_werror(status);
354                 goto done;
355         }
356
357  done:
358         if (cli) {
359                 cli_set_timeout(cli, old_timeout);
360                 cli_shutdown(cli);
361         }
362
363         return werr;
364 }
365
366 /****************************************************************
367 ****************************************************************/
368
369 static WERROR libnetapi_NetUnjoinDomain(struct libnetapi_ctx *ctx,
370                                         const char *server_name,
371                                         const char *account,
372                                         const char *password,
373                                         uint32_t unjoin_flags)
374 {
375         if (!server_name || is_myname_or_ipaddr(server_name)) {
376
377                 return NetUnjoinDomainLocal(ctx,
378                                             server_name,
379                                             account,
380                                             password,
381                                             unjoin_flags);
382         }
383
384         return NetUnjoinDomainRemote(ctx,
385                                      server_name,
386                                      account,
387                                      password,
388                                      unjoin_flags);
389 }
390
391 /****************************************************************
392  NetUnjoinDomain
393 ****************************************************************/
394
395 NET_API_STATUS NetUnjoinDomain(const char *server_name,
396                                const char *account,
397                                const char *password,
398                                uint32_t unjoin_flags)
399 {
400         struct libnetapi_ctx *ctx = NULL;
401         NET_API_STATUS status;
402         WERROR werr;
403
404         status = libnetapi_getctx(&ctx);
405         if (status != 0) {
406                 return status;
407         }
408
409         werr = libnetapi_NetUnjoinDomain(ctx,
410                                          server_name,
411                                          account,
412                                          password,
413                                          unjoin_flags);
414         if (!W_ERROR_IS_OK(werr)) {
415                 return W_ERROR_V(werr);
416         }
417
418         return NET_API_STATUS_SUCCESS;
419 }
420
421 /****************************************************************
422 ****************************************************************/
423
424 static WERROR NetGetJoinInformationRemote(struct libnetapi_ctx *ctx,
425                                           const char *server_name,
426                                           const char **name_buffer,
427                                           uint16_t *name_type)
428 {
429         struct cli_state *cli = NULL;
430         struct rpc_pipe_client *pipe_cli = NULL;
431         NTSTATUS status;
432         WERROR werr;
433
434         status = cli_full_connection(&cli, NULL, server_name,
435                                      NULL, 0,
436                                      "IPC$", "IPC",
437                                      ctx->username,
438                                      ctx->workgroup,
439                                      ctx->password,
440                                      0, Undefined, NULL);
441
442         if (!NT_STATUS_IS_OK(status)) {
443                 werr = ntstatus_to_werror(status);
444                 goto done;
445         }
446
447         pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_WKSSVC,
448                                             &status);
449         if (!pipe_cli) {
450                 werr = ntstatus_to_werror(status);
451                 goto done;
452         }
453
454         status = rpccli_wkssvc_NetrGetJoinInformation(pipe_cli, ctx,
455                                                       server_name,
456                                                       name_buffer,
457                                                       (enum wkssvc_NetJoinStatus *)name_type,
458                                                       &werr);
459         if (!NT_STATUS_IS_OK(status)) {
460                 werr = ntstatus_to_werror(status);
461                 goto done;
462         }
463
464  done:
465         if (cli) {
466                 cli_shutdown(cli);
467         }
468
469         return werr;
470 }
471
472 /****************************************************************
473 ****************************************************************/
474
475 static WERROR NetGetJoinInformationLocal(struct libnetapi_ctx *ctx,
476                                          const char *server_name,
477                                          const char **name_buffer,
478                                          uint16_t *name_type)
479 {
480         if ((lp_security() == SEC_ADS) && lp_realm()) {
481                 *name_buffer = talloc_strdup(ctx, lp_realm());
482         } else {
483                 *name_buffer = talloc_strdup(ctx, lp_workgroup());
484         }
485         if (!*name_buffer) {
486                 return WERR_NOMEM;
487         }
488
489         switch (lp_server_role()) {
490                 case ROLE_DOMAIN_MEMBER:
491                 case ROLE_DOMAIN_PDC:
492                 case ROLE_DOMAIN_BDC:
493                         *name_type = NetSetupDomainName;
494                         break;
495                 case ROLE_STANDALONE:
496                 default:
497                         *name_type = NetSetupWorkgroupName;
498                         break;
499         }
500
501         return WERR_OK;
502 }
503
504 static WERROR libnetapi_NetGetJoinInformation(struct libnetapi_ctx *ctx,
505                                               const char *server_name,
506                                               const char **name_buffer,
507                                               uint16_t *name_type)
508 {
509         if (!server_name || is_myname_or_ipaddr(server_name)) {
510                 return NetGetJoinInformationLocal(ctx,
511                                                   server_name,
512                                                   name_buffer,
513                                                   name_type);
514         }
515
516         return NetGetJoinInformationRemote(ctx,
517                                            server_name,
518                                            name_buffer,
519                                            name_type);
520 }
521
522 /****************************************************************
523  NetGetJoinInformation
524 ****************************************************************/
525
526 NET_API_STATUS NetGetJoinInformation(const char *server_name,
527                                      const char **name_buffer,
528                                      uint16_t *name_type)
529 {
530         struct libnetapi_ctx *ctx = NULL;
531         NET_API_STATUS status;
532         WERROR werr;
533
534         status = libnetapi_getctx(&ctx);
535         if (status != 0) {
536                 return status;
537         }
538
539         werr = libnetapi_NetGetJoinInformation(ctx,
540                                                server_name,
541                                                name_buffer,
542                                                name_type);
543         if (!W_ERROR_IS_OK(werr)) {
544                 return W_ERROR_V(werr);
545         }
546
547         return NET_API_STATUS_SUCCESS;
548 }
549
550 /****************************************************************
551 ****************************************************************/
552
553 static WERROR NetGetJoinableOUsLocal(struct libnetapi_ctx *ctx,
554                                      const char *server_name,
555                                      const char *domain,
556                                      const char *account,
557                                      const char *password,
558                                      uint32_t *ou_count,
559                                      const char ***ous)
560 {
561 #ifdef WITH_ADS
562         NTSTATUS status;
563         ADS_STATUS ads_status;
564         ADS_STRUCT *ads = NULL;
565         struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
566         uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
567                          DS_RETURN_DNS_NAME;
568
569         status = dsgetdcname(ctx, domain,
570                              NULL, NULL, flags, &info);
571         if (!NT_STATUS_IS_OK(status)) {
572                 libnetapi_set_error_string(ctx, "%s",
573                         get_friendly_nt_error_msg(status));
574                 return ntstatus_to_werror(status);
575         }
576
577         ads = ads_init(domain, domain, info->domain_controller_name);
578         if (!ads) {
579                 return WERR_GENERAL_FAILURE;
580         }
581
582         SAFE_FREE(ads->auth.user_name);
583         if (account) {
584                 ads->auth.user_name = SMB_STRDUP(account);
585         } else if (ctx->username) {
586                 ads->auth.user_name = SMB_STRDUP(ctx->username);
587         }
588
589         SAFE_FREE(ads->auth.password);
590         if (password) {
591                 ads->auth.password = SMB_STRDUP(password);
592         } else if (ctx->password) {
593                 ads->auth.password = SMB_STRDUP(ctx->password);
594         }
595
596         ads_status = ads_connect(ads);
597         if (!ADS_ERR_OK(ads_status)) {
598                 ads_destroy(&ads);
599                 return WERR_DEFAULT_JOIN_REQUIRED;
600         }
601
602         ads_status = ads_get_joinable_ous(ads, ctx,
603                                           (char ***)ous,
604                                           (size_t *)ou_count);
605         if (!ADS_ERR_OK(ads_status)) {
606                 ads_destroy(&ads);
607                 return WERR_DEFAULT_JOIN_REQUIRED;
608         }
609
610         ads_destroy(&ads);
611         return WERR_OK;
612 #else
613         return WERR_NOT_SUPPORTED;
614 #endif
615 }
616
617 /****************************************************************
618 ****************************************************************/
619
620 static WERROR NetGetJoinableOUsRemote(struct libnetapi_ctx *ctx,
621                                       const char *server_name,
622                                       const char *domain,
623                                       const char *account,
624                                       const char *password,
625                                       uint32_t *ou_count,
626                                       const char ***ous)
627 {
628         struct cli_state *cli = NULL;
629         struct rpc_pipe_client *pipe_cli = NULL;
630         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
631         NTSTATUS status;
632         WERROR werr;
633
634         status = cli_full_connection(&cli, NULL, server_name,
635                                      NULL, 0,
636                                      "IPC$", "IPC",
637                                      ctx->username,
638                                      ctx->workgroup,
639                                      ctx->password,
640                                      0, Undefined, NULL);
641
642         if (!NT_STATUS_IS_OK(status)) {
643                 werr = ntstatus_to_werror(status);
644                 goto done;
645         }
646
647         pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_WKSSVC,
648                                             &status);
649         if (!pipe_cli) {
650                 werr = ntstatus_to_werror(status);
651                 goto done;
652         }
653
654         if (password) {
655                 encode_wkssvc_join_password_buffer(ctx,
656                                                    password,
657                                                    &cli->user_session_key,
658                                                    &encrypted_password);
659         }
660
661         status = rpccli_wkssvc_NetrGetJoinableOus2(pipe_cli, ctx,
662                                                    server_name,
663                                                    domain,
664                                                    account,
665                                                    encrypted_password,
666                                                    ou_count,
667                                                    ous,
668                                                    &werr);
669         if (!NT_STATUS_IS_OK(status)) {
670                 werr = ntstatus_to_werror(status);
671                 goto done;
672         }
673
674  done:
675         if (cli) {
676                 cli_shutdown(cli);
677         }
678
679         return werr;
680 }
681
682 /****************************************************************
683 ****************************************************************/
684
685 static WERROR libnetapi_NetGetJoinableOUs(struct libnetapi_ctx *ctx,
686                                           const char *server_name,
687                                           const char *domain,
688                                           const char *account,
689                                           const char *password,
690                                           uint32_t *ou_count,
691                                           const char ***ous)
692 {
693         if (!server_name || is_myname_or_ipaddr(server_name)) {
694                 return NetGetJoinableOUsLocal(ctx,
695                                               server_name,
696                                               domain,
697                                               account,
698                                               password,
699                                               ou_count,
700                                               ous);
701         }
702
703         return NetGetJoinableOUsRemote(ctx,
704                                        server_name,
705                                        domain,
706                                        account,
707                                        password,
708                                        ou_count,
709                                        ous);
710 }
711
712 /****************************************************************
713  NetGetJoinableOUs
714 ****************************************************************/
715
716 NET_API_STATUS NetGetJoinableOUs(const char *server_name,
717                                  const char *domain,
718                                  const char *account,
719                                  const char *password,
720                                  uint32_t *ou_count,
721                                  const char ***ous)
722 {
723         struct libnetapi_ctx *ctx = NULL;
724         NET_API_STATUS status;
725         WERROR werr;
726
727         status = libnetapi_getctx(&ctx);
728         if (status != 0) {
729                 return status;
730         }
731
732         werr = libnetapi_NetGetJoinableOUs(ctx,
733                                            server_name,
734                                            domain,
735                                            account,
736                                            password,
737                                            ou_count,
738                                            ous);
739         if (!W_ERROR_IS_OK(werr)) {
740                 return W_ERROR_V(werr);
741         }
742
743         return NET_API_STATUS_SUCCESS;
744 }