netapi: fix returned name buffer in NetGetJoinInformation_r().
[samba.git] / source3 / lib / netapi / joindomain.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi Join Support
4  *  Copyright (C) Guenther Deschner 2007-2008
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
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
28 /****************************************************************
29 ****************************************************************/
30
31 WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
32                        struct NetJoinDomain *r)
33 {
34         struct libnet_JoinCtx *j = NULL;
35         WERROR werr;
36
37         if (!r->in.domain) {
38                 return WERR_INVALID_PARAM;
39         }
40
41         werr = libnet_init_JoinCtx(mem_ctx, &j);
42         W_ERROR_NOT_OK_RETURN(werr);
43
44         j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain);
45         W_ERROR_HAVE_NO_MEMORY(j->in.domain_name);
46
47         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
48                 NTSTATUS status;
49                 struct netr_DsRGetDCNameInfo *info = NULL;
50                 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
51                                  DS_WRITABLE_REQUIRED |
52                                  DS_RETURN_DNS_NAME;
53                 status = dsgetdcname(mem_ctx, r->in.domain,
54                                      NULL, NULL, flags, &info);
55                 if (!NT_STATUS_IS_OK(status)) {
56                         libnetapi_set_error_string(mem_ctx,
57                                 "%s", get_friendly_nt_error_msg(status));
58                         return ntstatus_to_werror(status);
59                 }
60                 j->in.dc_name = talloc_strdup(mem_ctx,
61                                               info->dc_unc);
62                 W_ERROR_HAVE_NO_MEMORY(j->in.dc_name);
63         }
64
65         if (r->in.account_ou) {
66                 j->in.account_ou = talloc_strdup(mem_ctx, r->in.account_ou);
67                 W_ERROR_HAVE_NO_MEMORY(j->in.account_ou);
68         }
69
70         if (r->in.account) {
71                 j->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
72                 W_ERROR_HAVE_NO_MEMORY(j->in.admin_account);
73         }
74
75         if (r->in.password) {
76                 j->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
77                 W_ERROR_HAVE_NO_MEMORY(j->in.admin_password);
78         }
79
80         j->in.join_flags = r->in.join_flags;
81         j->in.modify_config = true;
82         j->in.debug = true;
83
84         werr = libnet_Join(mem_ctx, j);
85         if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
86                 libnetapi_set_error_string(mem_ctx, "%s", j->out.error_string);
87         }
88         TALLOC_FREE(j);
89
90         return werr;
91 }
92
93 /****************************************************************
94 ****************************************************************/
95
96 WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx,
97                        struct NetJoinDomain *r)
98 {
99         struct cli_state *cli = NULL;
100         struct rpc_pipe_client *pipe_cli = NULL;
101         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
102         NTSTATUS status;
103         WERROR werr;
104         unsigned int old_timeout = 0;
105
106         werr = libnetapi_open_ipc_connection(ctx, r->in.server, &cli);
107         if (!W_ERROR_IS_OK(werr)) {
108                 goto done;
109         }
110
111         werr = libnetapi_open_pipe(ctx, cli, PI_WKSSVC, &pipe_cli);
112         if (!W_ERROR_IS_OK(werr)) {
113                 goto done;
114         }
115
116         if (r->in.password) {
117                 encode_wkssvc_join_password_buffer(ctx,
118                                                    r->in.password,
119                                                    &cli->user_session_key,
120                                                    &encrypted_password);
121         }
122
123         old_timeout = cli_set_timeout(cli, 600000);
124
125         status = rpccli_wkssvc_NetrJoinDomain2(pipe_cli, ctx,
126                                                r->in.server,
127                                                r->in.domain,
128                                                r->in.account_ou,
129                                                r->in.account,
130                                                encrypted_password,
131                                                r->in.join_flags,
132                                                &werr);
133         if (!NT_STATUS_IS_OK(status)) {
134                 werr = ntstatus_to_werror(status);
135                 goto done;
136         }
137
138  done:
139         if (cli) {
140                 if (old_timeout) {
141                         cli_set_timeout(cli, old_timeout);
142                 }
143         }
144
145         return werr;
146 }
147 /****************************************************************
148 ****************************************************************/
149
150 WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
151                          struct NetUnjoinDomain *r)
152 {
153         struct libnet_UnjoinCtx *u = NULL;
154         struct dom_sid domain_sid;
155         const char *domain = NULL;
156         WERROR werr;
157
158         if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
159                 return WERR_SETUP_NOT_JOINED;
160         }
161
162         werr = libnet_init_UnjoinCtx(mem_ctx, &u);
163         W_ERROR_NOT_OK_RETURN(werr);
164
165         if (lp_realm()) {
166                 domain = lp_realm();
167         } else {
168                 domain = lp_workgroup();
169         }
170
171         if (r->in.server_name) {
172                 u->in.dc_name = talloc_strdup(mem_ctx, r->in.server_name);
173                 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
174         } else {
175                 NTSTATUS status;
176                 struct netr_DsRGetDCNameInfo *info = NULL;
177                 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
178                                  DS_WRITABLE_REQUIRED |
179                                  DS_RETURN_DNS_NAME;
180                 status = dsgetdcname(mem_ctx, domain,
181                                      NULL, NULL, flags, &info);
182                 if (!NT_STATUS_IS_OK(status)) {
183                         libnetapi_set_error_string(mem_ctx,
184                                 "failed to find DC for domain %s: %s",
185                                 domain,
186                                 get_friendly_nt_error_msg(status));
187                         return ntstatus_to_werror(status);
188                 }
189                 u->in.dc_name = talloc_strdup(mem_ctx,
190                                               info->dc_unc);
191                 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
192
193                 u->in.domain_name = domain;
194         }
195
196         if (r->in.account) {
197                 u->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
198                 W_ERROR_HAVE_NO_MEMORY(u->in.admin_account);
199         }
200
201         if (r->in.password) {
202                 u->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
203                 W_ERROR_HAVE_NO_MEMORY(u->in.admin_password);
204         }
205
206         u->in.domain_name = domain;
207         u->in.unjoin_flags = r->in.unjoin_flags;
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 cli_state *cli = NULL;
229         struct rpc_pipe_client *pipe_cli = NULL;
230         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
231         NTSTATUS status;
232         WERROR werr;
233         unsigned int old_timeout = 0;
234
235         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
236         if (!W_ERROR_IS_OK(werr)) {
237                 goto done;
238         }
239
240         werr = libnetapi_open_pipe(ctx, cli, PI_WKSSVC, &pipe_cli);
241         if (!W_ERROR_IS_OK(werr)) {
242                 goto done;
243         }
244
245         if (r->in.password) {
246                 encode_wkssvc_join_password_buffer(ctx,
247                                                    r->in.password,
248                                                    &cli->user_session_key,
249                                                    &encrypted_password);
250         }
251
252         old_timeout = cli_set_timeout(cli, 60000);
253
254         status = rpccli_wkssvc_NetrUnjoinDomain2(pipe_cli, ctx,
255                                                  r->in.server_name,
256                                                  r->in.account,
257                                                  encrypted_password,
258                                                  r->in.unjoin_flags,
259                                                  &werr);
260         if (!NT_STATUS_IS_OK(status)) {
261                 werr = ntstatus_to_werror(status);
262                 goto done;
263         }
264
265  done:
266         if (cli) {
267                 if (old_timeout) {
268                         cli_set_timeout(cli, old_timeout);
269                 }
270         }
271
272         return werr;
273 }
274
275 /****************************************************************
276 ****************************************************************/
277
278 WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
279                                struct NetGetJoinInformation *r)
280 {
281         struct cli_state *cli = NULL;
282         struct rpc_pipe_client *pipe_cli = NULL;
283         NTSTATUS status;
284         WERROR werr;
285         const char *buffer = NULL;
286
287         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
288         if (!W_ERROR_IS_OK(werr)) {
289                 goto done;
290         }
291
292         werr = libnetapi_open_pipe(ctx, cli, PI_WKSSVC, &pipe_cli);
293         if (!W_ERROR_IS_OK(werr)) {
294                 goto done;
295         }
296
297         status = rpccli_wkssvc_NetrGetJoinInformation(pipe_cli, ctx,
298                                                       r->in.server_name,
299                                                       &buffer,
300                                                       (enum wkssvc_NetJoinStatus *)r->out.name_type,
301                                                       &werr);
302         if (!NT_STATUS_IS_OK(status)) {
303                 werr = ntstatus_to_werror(status);
304                 goto done;
305         }
306
307         *r->out.name_buffer = talloc_strdup(ctx, buffer);
308         W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer);
309
310  done:
311         return werr;
312 }
313
314 /****************************************************************
315 ****************************************************************/
316
317 WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
318                                struct NetGetJoinInformation *r)
319 {
320         if ((lp_security() == SEC_ADS) && lp_realm()) {
321                 *r->out.name_buffer = talloc_strdup(ctx, lp_realm());
322         } else {
323                 *r->out.name_buffer = talloc_strdup(ctx, lp_workgroup());
324         }
325         if (!*r->out.name_buffer) {
326                 return WERR_NOMEM;
327         }
328
329         switch (lp_server_role()) {
330                 case ROLE_DOMAIN_MEMBER:
331                 case ROLE_DOMAIN_PDC:
332                 case ROLE_DOMAIN_BDC:
333                         *r->out.name_type = NetSetupDomainName;
334                         break;
335                 case ROLE_STANDALONE:
336                 default:
337                         *r->out.name_type = NetSetupWorkgroupName;
338                         break;
339         }
340
341         return WERR_OK;
342 }
343
344 /****************************************************************
345 ****************************************************************/
346
347 WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
348                            struct NetGetJoinableOUs *r)
349 {
350 #ifdef WITH_ADS
351         NTSTATUS status;
352         ADS_STATUS ads_status;
353         ADS_STRUCT *ads = NULL;
354         struct netr_DsRGetDCNameInfo *info = NULL;
355         uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
356                          DS_RETURN_DNS_NAME;
357
358         status = dsgetdcname(ctx, r->in.domain,
359                              NULL, NULL, flags, &info);
360         if (!NT_STATUS_IS_OK(status)) {
361                 libnetapi_set_error_string(ctx, "%s",
362                         get_friendly_nt_error_msg(status));
363                 return ntstatus_to_werror(status);
364         }
365
366         ads = ads_init(r->in.domain, r->in.domain, info->dc_unc);
367         if (!ads) {
368                 return WERR_GENERAL_FAILURE;
369         }
370
371         SAFE_FREE(ads->auth.user_name);
372         if (r->in.account) {
373                 ads->auth.user_name = SMB_STRDUP(r->in.account);
374         } else if (ctx->username) {
375                 ads->auth.user_name = SMB_STRDUP(ctx->username);
376         }
377
378         SAFE_FREE(ads->auth.password);
379         if (r->in.password) {
380                 ads->auth.password = SMB_STRDUP(r->in.password);
381         } else if (ctx->password) {
382                 ads->auth.password = SMB_STRDUP(ctx->password);
383         }
384
385         ads_status = ads_connect(ads);
386         if (!ADS_ERR_OK(ads_status)) {
387                 ads_destroy(&ads);
388                 return WERR_DEFAULT_JOIN_REQUIRED;
389         }
390
391         ads_status = ads_get_joinable_ous(ads, ctx,
392                                           (char ***)r->out.ous,
393                                           (size_t *)r->out.ou_count);
394         if (!ADS_ERR_OK(ads_status)) {
395                 ads_destroy(&ads);
396                 return WERR_DEFAULT_JOIN_REQUIRED;
397         }
398
399         ads_destroy(&ads);
400         return WERR_OK;
401 #else
402         return WERR_NOT_SUPPORTED;
403 #endif
404 }
405
406 /****************************************************************
407 ****************************************************************/
408
409 WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
410                            struct NetGetJoinableOUs *r)
411 {
412         struct cli_state *cli = NULL;
413         struct rpc_pipe_client *pipe_cli = NULL;
414         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
415         NTSTATUS status;
416         WERROR werr;
417
418         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
419         if (!W_ERROR_IS_OK(werr)) {
420                 goto done;
421         }
422
423         werr = libnetapi_open_pipe(ctx, cli, PI_WKSSVC, &pipe_cli);
424         if (!W_ERROR_IS_OK(werr)) {
425                 goto done;
426         }
427
428         if (r->in.password) {
429                 encode_wkssvc_join_password_buffer(ctx,
430                                                    r->in.password,
431                                                    &cli->user_session_key,
432                                                    &encrypted_password);
433         }
434
435         status = rpccli_wkssvc_NetrGetJoinableOus2(pipe_cli, ctx,
436                                                    r->in.server_name,
437                                                    r->in.domain,
438                                                    r->in.account,
439                                                    encrypted_password,
440                                                    r->out.ou_count,
441                                                    r->out.ous,
442                                                    &werr);
443         if (!NT_STATUS_IS_OK(status)) {
444                 werr = ntstatus_to_werror(status);
445                 goto done;
446         }
447
448  done:
449         if (cli) {
450                 cli_shutdown(cli);
451         }
452
453         return werr;
454 }