Add NetGetJoinableOUs() to libnetapi (incl. example).
[nivanova/samba-autobuild/.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, NULL, 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, NULL, 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         NTSTATUS status;
562         ADS_STATUS ads_status;
563         ADS_STRUCT *ads = NULL;
564         struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
565         uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
566                          DS_RETURN_DNS_NAME;
567
568         status = dsgetdcname(ctx, NULL, domain,
569                              NULL, NULL, flags, &info);
570         if (!NT_STATUS_IS_OK(status)) {
571                 libnetapi_set_error_string(ctx, "%s",
572                         get_friendly_nt_error_msg(status));
573                 return ntstatus_to_werror(status);
574         }
575
576         ads = ads_init(domain, domain, info->domain_controller_name);
577         if (!ads) {
578                 return WERR_GENERAL_FAILURE;
579         }
580
581         SAFE_FREE(ads->auth.user_name);
582         if (account) {
583                 ads->auth.user_name = SMB_STRDUP(account);
584         } else if (ctx->username) {
585                 ads->auth.user_name = SMB_STRDUP(ctx->username);
586         }
587
588         SAFE_FREE(ads->auth.password);
589         if (password) {
590                 ads->auth.password = SMB_STRDUP(password);
591         } else if (ctx->password) {
592                 ads->auth.password = SMB_STRDUP(ctx->password);
593         }
594
595         ads_status = ads_connect(ads);
596         if (!ADS_ERR_OK(ads_status)) {
597                 ads_destroy(&ads);
598                 return WERR_DEFAULT_JOIN_REQUIRED;
599         }
600
601         ads_status = ads_get_joinable_ous(ads, ctx,
602                                           (char ***)ous,
603                                           (size_t *)ou_count);
604         if (!ADS_ERR_OK(ads_status)) {
605                 ads_destroy(&ads);
606                 return WERR_DEFAULT_JOIN_REQUIRED;
607         }
608
609         ads_destroy(&ads);
610         return WERR_OK;
611 }
612
613 /****************************************************************
614 ****************************************************************/
615
616 static WERROR NetGetJoinableOUsRemote(struct libnetapi_ctx *ctx,
617                                       const char *server_name,
618                                       const char *domain,
619                                       const char *account,
620                                       const char *password,
621                                       uint32_t *ou_count,
622                                       const char ***ous)
623 {
624         struct cli_state *cli = NULL;
625         struct rpc_pipe_client *pipe_cli = NULL;
626         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
627         NTSTATUS status;
628         WERROR werr;
629
630         status = cli_full_connection(&cli, NULL, server_name,
631                                      NULL, 0,
632                                      "IPC$", "IPC",
633                                      ctx->username,
634                                      ctx->workgroup,
635                                      ctx->password,
636                                      0, Undefined, NULL);
637
638         if (!NT_STATUS_IS_OK(status)) {
639                 werr = ntstatus_to_werror(status);
640                 goto done;
641         }
642
643         pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_WKSSVC,
644                                             &status);
645         if (!pipe_cli) {
646                 werr = ntstatus_to_werror(status);
647                 goto done;
648         }
649
650         if (password) {
651                 encode_wkssvc_join_password_buffer(ctx,
652                                                    password,
653                                                    &cli->user_session_key,
654                                                    &encrypted_password);
655         }
656
657         status = rpccli_wkssvc_NetrGetJoinableOus2(pipe_cli, ctx,
658                                                    server_name,
659                                                    domain,
660                                                    account,
661                                                    encrypted_password,
662                                                    ou_count,
663                                                    ous,
664                                                    &werr);
665         if (!NT_STATUS_IS_OK(status)) {
666                 werr = ntstatus_to_werror(status);
667                 goto done;
668         }
669
670  done:
671         if (cli) {
672                 cli_shutdown(cli);
673         }
674
675         return werr;
676 }
677
678 /****************************************************************
679 ****************************************************************/
680
681 static WERROR libnetapi_NetGetJoinableOUs(struct libnetapi_ctx *ctx,
682                                           const char *server_name,
683                                           const char *domain,
684                                           const char *account,
685                                           const char *password,
686                                           uint32_t *ou_count,
687                                           const char ***ous)
688 {
689         if (!server_name || is_myname_or_ipaddr(server_name)) {
690                 return NetGetJoinableOUsLocal(ctx,
691                                               server_name,
692                                               domain,
693                                               account,
694                                               password,
695                                               ou_count,
696                                               ous);
697         }
698
699         return NetGetJoinableOUsRemote(ctx,
700                                        server_name,
701                                        domain,
702                                        account,
703                                        password,
704                                        ou_count,
705                                        ous);
706 }
707
708 /****************************************************************
709  NetGetJoinableOUs
710 ****************************************************************/
711
712 NET_API_STATUS NetGetJoinableOUs(const char *server_name,
713                                  const char *domain,
714                                  const char *account,
715                                  const char *password,
716                                  uint32_t *ou_count,
717                                  const char ***ous)
718 {
719         struct libnetapi_ctx *ctx = NULL;
720         NET_API_STATUS status;
721         WERROR werr;
722
723         status = libnetapi_getctx(&ctx);
724         if (status != 0) {
725                 return status;
726         }
727
728         werr = libnetapi_NetGetJoinableOUs(ctx,
729                                            server_name,
730                                            domain,
731                                            account,
732                                            password,
733                                            ou_count,
734                                            ous);
735         if (!W_ERROR_IS_OK(werr)) {
736                 return W_ERROR_V(werr);
737         }
738
739         return NET_API_STATUS_SUCCESS;
740 }