Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Helper routines for net
4 : * Copyright (C) Volker Lendecke 2006
5 : * Copyright (C) Kai Blin 2008
6 : *
7 : * This program is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * This program is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 :
22 : #include "includes.h"
23 : #include "utils/net.h"
24 : #include "libsmb/namequery.h"
25 : #include "rpc_client/cli_pipe.h"
26 : #include "../librpc/gen_ndr/ndr_lsa_c.h"
27 : #include "rpc_client/cli_lsarpc.h"
28 : #include "../librpc/gen_ndr/ndr_dssetup_c.h"
29 : #include "secrets.h"
30 : #include "../libcli/security/security.h"
31 : #include "libsmb/libsmb.h"
32 : #include "lib/param/param.h"
33 : #include "auth/gensec/gensec.h"
34 : #include "libcli/auth/netlogon_creds_cli.h"
35 : #include "lib/cmdline/cmdline.h"
36 :
37 0 : NTSTATUS net_rpc_lookup_name(struct net_context *c,
38 : TALLOC_CTX *mem_ctx, struct cli_state *cli,
39 : const char *name, const char **ret_domain,
40 : const char **ret_name, struct dom_sid *ret_sid,
41 : enum lsa_SidType *ret_type)
42 : {
43 0 : struct rpc_pipe_client *lsa_pipe = NULL;
44 0 : struct policy_handle pol;
45 0 : NTSTATUS status, result;
46 0 : const char **dom_names;
47 0 : struct dom_sid *sids;
48 0 : enum lsa_SidType *types;
49 0 : struct dcerpc_binding_handle *b;
50 :
51 0 : ZERO_STRUCT(pol);
52 :
53 0 : status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
54 : &lsa_pipe);
55 0 : if (!NT_STATUS_IS_OK(status)) {
56 0 : d_fprintf(stderr, _("Could not initialise lsa pipe\n"));
57 0 : return status;
58 : }
59 :
60 0 : b = lsa_pipe->binding_handle;
61 :
62 0 : status = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, false,
63 : SEC_FLAG_MAXIMUM_ALLOWED,
64 : &pol);
65 0 : if (!NT_STATUS_IS_OK(status)) {
66 0 : d_fprintf(stderr, "open_policy %s: %s\n", _("failed"),
67 : nt_errstr(status));
68 0 : return status;
69 : }
70 :
71 0 : status = rpccli_lsa_lookup_names(lsa_pipe, mem_ctx, &pol, 1,
72 : &name, &dom_names, 1, &sids, &types);
73 :
74 0 : if (!NT_STATUS_IS_OK(status)) {
75 : /* This can happen easily, don't log an error */
76 0 : goto done;
77 : }
78 :
79 0 : if (ret_domain != NULL) {
80 0 : *ret_domain = dom_names[0];
81 : }
82 0 : if (ret_name != NULL) {
83 0 : *ret_name = talloc_strdup(mem_ctx, name);
84 : }
85 0 : if (ret_sid != NULL) {
86 0 : sid_copy(ret_sid, &sids[0]);
87 : }
88 0 : if (ret_type != NULL) {
89 0 : *ret_type = types[0];
90 : }
91 :
92 0 : done:
93 0 : if (is_valid_policy_hnd(&pol)) {
94 0 : dcerpc_lsa_Close(b, mem_ctx, &pol, &result);
95 : }
96 0 : TALLOC_FREE(lsa_pipe);
97 :
98 0 : return status;
99 : }
100 :
101 : /****************************************************************************
102 : Connect to \\server\service.
103 : ****************************************************************************/
104 :
105 876 : NTSTATUS connect_to_service(struct net_context *c,
106 : struct cli_state **cli_ctx,
107 : const struct sockaddr_storage *server_ss,
108 : const char *server_name,
109 : const char *service_name,
110 : const char *service_type)
111 : {
112 0 : NTSTATUS nt_status;
113 876 : int flags = 0;
114 :
115 876 : if (strequal(service_type, "IPC")) {
116 876 : flags |= CLI_FULL_CONNECTION_IPC;
117 : }
118 :
119 876 : nt_status = cli_full_connection_creds(cli_ctx, NULL, server_name,
120 : server_ss, c->opt_port,
121 : service_name, service_type,
122 : c->creds,
123 : flags);
124 876 : if (!NT_STATUS_IS_OK(nt_status)) {
125 4 : d_fprintf(stderr, _("Could not connect to server %s\n"),
126 : server_name);
127 :
128 : /* Display a nicer message depending on the result */
129 :
130 4 : if (NT_STATUS_V(nt_status) ==
131 4 : NT_STATUS_V(NT_STATUS_LOGON_FAILURE))
132 0 : d_fprintf(stderr,
133 0 : _("The username or password was not "
134 : "correct.\n"));
135 :
136 4 : if (NT_STATUS_V(nt_status) ==
137 4 : NT_STATUS_V(NT_STATUS_ACCOUNT_LOCKED_OUT))
138 0 : d_fprintf(stderr, _("The account was locked out.\n"));
139 :
140 4 : if (NT_STATUS_V(nt_status) ==
141 4 : NT_STATUS_V(NT_STATUS_ACCOUNT_DISABLED))
142 0 : d_fprintf(stderr, _("The account was disabled.\n"));
143 4 : return nt_status;
144 : }
145 :
146 872 : return nt_status;
147 : }
148 :
149 : /****************************************************************************
150 : Connect to \\server\ipc$.
151 : ****************************************************************************/
152 :
153 876 : NTSTATUS connect_to_ipc(struct net_context *c,
154 : struct cli_state **cli_ctx,
155 : const struct sockaddr_storage *server_ss,
156 : const char *server_name)
157 : {
158 876 : return connect_to_service(c, cli_ctx, server_ss, server_name, "IPC$",
159 : "IPC");
160 : }
161 :
162 : /****************************************************************************
163 : Connect to \\server\ipc$ anonymously.
164 : ****************************************************************************/
165 :
166 10 : NTSTATUS connect_to_ipc_anonymous(struct net_context *c,
167 : struct cli_state **cli_ctx,
168 : const struct sockaddr_storage *server_ss,
169 : const char *server_name)
170 : {
171 0 : NTSTATUS nt_status;
172 10 : struct cli_credentials *anon_creds = NULL;
173 :
174 10 : anon_creds = cli_credentials_init_anon(c);
175 10 : if (anon_creds == NULL) {
176 0 : DBG_ERR("cli_credentials_init_anon() failed\n");
177 0 : return NT_STATUS_NO_MEMORY;
178 : }
179 :
180 10 : nt_status = cli_full_connection_creds(cli_ctx, c->opt_requester_name,
181 : server_name, server_ss, c->opt_port,
182 : "IPC$", "IPC",
183 : anon_creds,
184 : CLI_FULL_CONNECTION_IPC);
185 :
186 10 : if (NT_STATUS_IS_OK(nt_status)) {
187 10 : return nt_status;
188 : } else {
189 0 : DEBUG(1,("Cannot connect to server (anonymously). Error was %s\n", nt_errstr(nt_status)));
190 0 : return nt_status;
191 : }
192 : }
193 :
194 : /**
195 : * Connect a server and open a given pipe
196 : *
197 : * @param cli_dst A cli_state
198 : * @param pipe The pipe to open
199 : * @param got_pipe boolean that stores if we got a pipe
200 : *
201 : * @return Normal NTSTATUS return.
202 : **/
203 0 : NTSTATUS connect_dst_pipe(struct net_context *c, struct cli_state **cli_dst,
204 : struct rpc_pipe_client **pp_pipe_hnd,
205 : const struct ndr_interface_table *table)
206 : {
207 0 : NTSTATUS nt_status;
208 0 : char *server_name = SMB_STRDUP("127.0.0.1");
209 0 : struct cli_state *cli_tmp = NULL;
210 0 : struct rpc_pipe_client *pipe_hnd = NULL;
211 :
212 0 : if (server_name == NULL) {
213 0 : return NT_STATUS_NO_MEMORY;
214 : }
215 :
216 0 : if (c->opt_destination) {
217 0 : SAFE_FREE(server_name);
218 0 : if ((server_name = SMB_STRDUP(c->opt_destination)) == NULL) {
219 0 : return NT_STATUS_NO_MEMORY;
220 : }
221 : }
222 :
223 : /* make a connection to a named pipe */
224 0 : nt_status = connect_to_ipc(c, &cli_tmp, NULL, server_name);
225 0 : if (!NT_STATUS_IS_OK(nt_status)) {
226 0 : SAFE_FREE(server_name);
227 0 : return nt_status;
228 : }
229 :
230 0 : nt_status = cli_rpc_pipe_open_noauth(cli_tmp, table,
231 : &pipe_hnd);
232 0 : if (!NT_STATUS_IS_OK(nt_status)) {
233 0 : DEBUG(0, ("couldn't not initialize pipe\n"));
234 0 : cli_shutdown(cli_tmp);
235 0 : SAFE_FREE(server_name);
236 0 : return nt_status;
237 : }
238 :
239 0 : *cli_dst = cli_tmp;
240 0 : *pp_pipe_hnd = pipe_hnd;
241 0 : SAFE_FREE(server_name);
242 :
243 0 : return nt_status;
244 : }
245 :
246 : /****************************************************************************
247 : Use the local machine account (krb) and password for this session.
248 : ****************************************************************************/
249 :
250 40 : int net_use_krb_machine_account(struct net_context *c)
251 : {
252 40 : char *user_name = NULL;
253 :
254 40 : if (!secrets_init()) {
255 0 : d_fprintf(stderr,_("ERROR: Unable to open secrets database\n"));
256 0 : exit(1);
257 : }
258 :
259 40 : c->opt_password = secrets_fetch_machine_password(
260 : c->opt_target_workgroup, NULL, NULL);
261 40 : if (asprintf(&user_name, "%s$@%s", lp_netbios_name(), lp_realm()) == -1) {
262 0 : return -1;
263 : }
264 40 : c->opt_user_name = user_name;
265 40 : c->opt_user_specified = true;
266 :
267 40 : cli_credentials_set_machine_account(c->creds, c->lp_ctx);
268 40 : return 0;
269 : }
270 :
271 882 : bool net_find_server(struct net_context *c,
272 : const char *domain,
273 : unsigned flags,
274 : struct sockaddr_storage *server_ss,
275 : char **server_name)
276 : {
277 882 : const char *d = domain ? domain : c->opt_target_workgroup;
278 :
279 882 : if (c->opt_host) {
280 180 : *server_name = SMB_STRDUP(c->opt_host);
281 : }
282 :
283 882 : if (c->opt_have_ip) {
284 698 : *server_ss = c->opt_dest_ip;
285 698 : if (!*server_name) {
286 0 : char addr[INET6_ADDRSTRLEN];
287 698 : print_sockaddr(addr, sizeof(addr), &c->opt_dest_ip);
288 698 : *server_name = SMB_STRDUP(addr);
289 : }
290 184 : } else if (*server_name) {
291 : /* resolve the IP address */
292 180 : if (!resolve_name(*server_name, server_ss, 0x20, false)) {
293 0 : DEBUG(1,("Unable to resolve server name\n"));
294 0 : return false;
295 : }
296 4 : } else if (flags & NET_FLAGS_PDC) {
297 0 : fstring dc_name;
298 0 : struct sockaddr_storage pdc_ss;
299 :
300 4 : if (!get_pdc_ip(d, &pdc_ss)) {
301 0 : DEBUG(1,("Unable to resolve PDC server address\n"));
302 0 : return false;
303 : }
304 :
305 4 : if (is_zero_addr(&pdc_ss)) {
306 0 : return false;
307 : }
308 :
309 4 : if (!name_status_find(d, 0x1b, 0x20, &pdc_ss, dc_name)) {
310 0 : return false;
311 : }
312 :
313 4 : *server_name = SMB_STRDUP(dc_name);
314 4 : *server_ss = pdc_ss;
315 0 : } else if (flags & NET_FLAGS_DMB) {
316 0 : struct sockaddr_storage msbrow_ss;
317 0 : char addr[INET6_ADDRSTRLEN];
318 :
319 : /* if (!resolve_name(MSBROWSE, &msbrow_ip, 1, false)) */
320 0 : if (!resolve_name(d, &msbrow_ss, 0x1B, false)) {
321 0 : DEBUG(1,("Unable to resolve domain browser via name lookup\n"));
322 0 : return false;
323 : }
324 0 : *server_ss = msbrow_ss;
325 0 : print_sockaddr(addr, sizeof(addr), server_ss);
326 0 : *server_name = SMB_STRDUP(addr);
327 0 : } else if (flags & NET_FLAGS_MASTER) {
328 0 : struct sockaddr_storage brow_ss;
329 0 : char addr[INET6_ADDRSTRLEN];
330 0 : if (!resolve_name(d, &brow_ss, 0x1D, false)) {
331 : /* go looking for workgroups */
332 0 : DEBUG(1,("Unable to resolve master browser via name lookup\n"));
333 0 : return false;
334 : }
335 0 : *server_ss = brow_ss;
336 0 : print_sockaddr(addr, sizeof(addr), server_ss);
337 0 : *server_name = SMB_STRDUP(addr);
338 0 : } else if (!(flags & NET_FLAGS_LOCALHOST_DEFAULT_INSANE)) {
339 0 : if (!interpret_string_addr(server_ss,
340 : "127.0.0.1", AI_NUMERICHOST)) {
341 0 : DEBUG(1,("Unable to resolve 127.0.0.1\n"));
342 0 : return false;
343 : }
344 0 : *server_name = SMB_STRDUP("127.0.0.1");
345 : }
346 :
347 882 : if (!*server_name) {
348 0 : DEBUG(1,("no server to connect to\n"));
349 0 : return false;
350 : }
351 :
352 882 : return true;
353 : }
354 :
355 4 : bool net_find_pdc(struct sockaddr_storage *server_ss,
356 : fstring server_name,
357 : const char *domain_name)
358 : {
359 4 : if (!get_pdc_ip(domain_name, server_ss)) {
360 0 : return false;
361 : }
362 4 : if (is_zero_addr(server_ss)) {
363 0 : return false;
364 : }
365 :
366 4 : if (!name_status_find(domain_name, 0x1b, 0x20, server_ss, server_name)) {
367 0 : return false;
368 : }
369 :
370 4 : return true;
371 : }
372 :
373 874 : NTSTATUS net_make_ipc_connection(struct net_context *c, unsigned flags,
374 : struct cli_state **pcli)
375 : {
376 874 : return net_make_ipc_connection_ex(c, c->opt_workgroup, NULL, NULL, flags, pcli);
377 : }
378 :
379 878 : NTSTATUS net_make_ipc_connection_ex(struct net_context *c ,const char *domain,
380 : const char *server,
381 : const struct sockaddr_storage *pss,
382 : unsigned flags, struct cli_state **pcli)
383 : {
384 878 : char *server_name = NULL;
385 0 : struct sockaddr_storage server_ss;
386 878 : struct cli_state *cli = NULL;
387 0 : NTSTATUS nt_status;
388 :
389 878 : if ( !server || !pss ) {
390 878 : if (!net_find_server(c, domain, flags, &server_ss,
391 : &server_name)) {
392 0 : d_fprintf(stderr, _("Unable to find a suitable server "
393 : "for domain %s\n"), domain);
394 0 : nt_status = NT_STATUS_UNSUCCESSFUL;
395 0 : goto done;
396 : }
397 : } else {
398 0 : server_name = SMB_STRDUP( server );
399 0 : server_ss = *pss;
400 : }
401 :
402 878 : if (flags & NET_FLAGS_ANONYMOUS) {
403 6 : nt_status = connect_to_ipc_anonymous(c, &cli, &server_ss,
404 : server_name);
405 : } else {
406 872 : nt_status = connect_to_ipc(c, &cli, &server_ss,
407 : server_name);
408 : }
409 :
410 : /* store the server in the affinity cache if it was a PDC */
411 :
412 878 : if ( (flags & NET_FLAGS_PDC) && NT_STATUS_IS_OK(nt_status) )
413 10 : saf_store(cli->server_domain, server_name);
414 :
415 878 : SAFE_FREE(server_name);
416 878 : if (!NT_STATUS_IS_OK(nt_status)) {
417 0 : d_fprintf(stderr, _("Connection failed: %s\n"),
418 : nt_errstr(nt_status));
419 0 : cli = NULL;
420 878 : } else if (c->opt_request_timeout) {
421 0 : cli_set_timeout(cli, c->opt_request_timeout * 1000);
422 : }
423 :
424 878 : done:
425 878 : if (pcli != NULL) {
426 878 : *pcli = cli;
427 : }
428 878 : return nt_status;
429 : }
430 :
431 : /****************************************************************************
432 : ****************************************************************************/
433 :
434 : /* TODO FIXME: Pass cli_creds via net_context and get rid of this function. */
435 199 : const char *net_prompt_pass(struct net_context *c, const char *user)
436 : {
437 199 : struct cli_credentials *creds = samba_cmdline_get_creds();
438 :
439 199 : if (c->opt_password == NULL) {
440 199 : c->opt_password = cli_credentials_get_password(creds);
441 : }
442 :
443 199 : return c->opt_password;
444 : }
445 :
446 7255 : int net_run_function(struct net_context *c, int argc, const char **argv,
447 : const char *whoami, struct functable *table)
448 : {
449 5 : int i;
450 :
451 7255 : if (argc != 0) {
452 96111 : for (i=0; table[i].funcname != NULL; i++) {
453 96111 : if (strcasecmp_m(argv[0], table[i].funcname) == 0)
454 7255 : return table[i].fn(c, argc-1, argv+1);
455 : }
456 : }
457 :
458 0 : if (c->display_usage == false) {
459 0 : d_fprintf(stderr, _("Invalid command: %s %s\n"), whoami,
460 : (argc > 0)?argv[0]:"");
461 : }
462 0 : d_printf(_("Usage:\n"));
463 0 : for (i=0; table[i].funcname != NULL; i++) {
464 0 : if(c->display_usage == false)
465 0 : d_printf("%s %-15s %s\n", whoami, table[i].funcname,
466 0 : _(table[i].description));
467 : else
468 0 : d_printf("%s\n", _(table[i].usage));
469 : }
470 :
471 0 : return c->display_usage?0:-1;
472 : }
473 :
474 0 : void net_display_usage_from_functable(struct functable *table)
475 : {
476 0 : int i;
477 0 : for (i=0; table[i].funcname != NULL; i++) {
478 0 : d_printf("%s\n", _(table[i].usage));
479 : }
480 0 : }
481 :
482 238 : void net_warn_member_options(void)
483 : {
484 238 : TALLOC_CTX *frame = talloc_stackframe();
485 238 : struct loadparm_context *lp_ctx = NULL;
486 :
487 238 : lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
488 238 : if (lp_ctx != NULL) {
489 238 : netlogon_creds_cli_warn_options(lp_ctx);
490 : }
491 :
492 238 : TALLOC_FREE(frame);
493 238 : }
494 :
495 0 : const char *net_share_type_str(int num_type)
496 : {
497 0 : switch(num_type) {
498 0 : case 0: return _("Disk");
499 0 : case 1: return _("Print");
500 0 : case 2: return _("Dev");
501 0 : case 3: return _("IPC");
502 0 : default: return _("Unknown");
503 : }
504 : }
505 :
506 0 : static NTSTATUS net_scan_dc_noad(struct net_context *c,
507 : struct cli_state *cli,
508 : struct net_dc_info *dc_info)
509 : {
510 0 : TALLOC_CTX *mem_ctx = talloc_tos();
511 0 : struct rpc_pipe_client *pipe_hnd = NULL;
512 0 : struct dcerpc_binding_handle *b;
513 0 : NTSTATUS status, result;
514 0 : struct policy_handle pol;
515 0 : union lsa_PolicyInformation *info;
516 :
517 0 : ZERO_STRUCTP(dc_info);
518 0 : ZERO_STRUCT(pol);
519 :
520 0 : status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
521 : &pipe_hnd);
522 0 : if (!NT_STATUS_IS_OK(status)) {
523 0 : return status;
524 : }
525 :
526 0 : b = pipe_hnd->binding_handle;
527 :
528 0 : status = dcerpc_lsa_open_policy(b, mem_ctx,
529 : false,
530 : SEC_FLAG_MAXIMUM_ALLOWED,
531 : &pol,
532 : &result);
533 0 : if (!NT_STATUS_IS_OK(status)) {
534 0 : goto done;
535 : }
536 0 : if (!NT_STATUS_IS_OK(result)) {
537 0 : status = result;
538 0 : goto done;
539 : }
540 :
541 0 : status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
542 : &pol,
543 : LSA_POLICY_INFO_ACCOUNT_DOMAIN,
544 : &info,
545 : &result);
546 0 : if (!NT_STATUS_IS_OK(status)) {
547 0 : goto done;
548 : }
549 0 : if (!NT_STATUS_IS_OK(result)) {
550 0 : status = result;
551 0 : goto done;
552 : }
553 :
554 0 : dc_info->netbios_domain_name = talloc_strdup(mem_ctx, info->account_domain.name.string);
555 0 : if (dc_info->netbios_domain_name == NULL) {
556 0 : status = NT_STATUS_NO_MEMORY;
557 0 : goto done;
558 : }
559 :
560 0 : done:
561 0 : if (is_valid_policy_hnd(&pol)) {
562 0 : dcerpc_lsa_Close(b, mem_ctx, &pol, &result);
563 : }
564 :
565 0 : TALLOC_FREE(pipe_hnd);
566 :
567 0 : return status;
568 : }
569 :
570 0 : NTSTATUS net_scan_dc(struct net_context *c,
571 : struct cli_state *cli,
572 : struct net_dc_info *dc_info)
573 : {
574 0 : TALLOC_CTX *mem_ctx = talloc_tos();
575 0 : struct rpc_pipe_client *dssetup_pipe = NULL;
576 0 : struct dcerpc_binding_handle *dssetup_handle = NULL;
577 0 : union dssetup_DsRoleInfo info;
578 0 : NTSTATUS status;
579 0 : WERROR werr;
580 :
581 0 : ZERO_STRUCTP(dc_info);
582 :
583 0 : status = cli_rpc_pipe_open_noauth(cli, &ndr_table_dssetup,
584 : &dssetup_pipe);
585 0 : if (!NT_STATUS_IS_OK(status)) {
586 0 : DEBUG(10,("net_scan_dc: failed to open dssetup pipe with %s, "
587 : "retrying with lsa pipe\n", nt_errstr(status)));
588 0 : return net_scan_dc_noad(c, cli, dc_info);
589 : }
590 0 : dssetup_handle = dssetup_pipe->binding_handle;
591 :
592 0 : status = dcerpc_dssetup_DsRoleGetPrimaryDomainInformation(dssetup_handle, mem_ctx,
593 : DS_ROLE_BASIC_INFORMATION,
594 : &info,
595 : &werr);
596 0 : TALLOC_FREE(dssetup_pipe);
597 :
598 0 : if (NT_STATUS_IS_OK(status)) {
599 0 : status = werror_to_ntstatus(werr);
600 : }
601 0 : if (!NT_STATUS_IS_OK(status)) {
602 0 : return status;
603 : }
604 :
605 0 : dc_info->is_dc = (info.basic.role & (DS_ROLE_PRIMARY_DC|DS_ROLE_BACKUP_DC));
606 0 : dc_info->is_pdc = (info.basic.role & DS_ROLE_PRIMARY_DC);
607 0 : dc_info->is_ad = (info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING);
608 0 : dc_info->is_mixed_mode = (info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE);
609 0 : dc_info->netbios_domain_name = talloc_strdup(mem_ctx, info.basic.domain);
610 0 : dc_info->dns_domain_name = talloc_strdup(mem_ctx, info.basic.dns_domain);
611 0 : dc_info->forest_name = talloc_strdup(mem_ctx, info.basic.forest);
612 :
613 0 : return NT_STATUS_OK;
614 : }
|