Line data Source code
1 : /*
2 : Samba Unix/Linux SMB client library
3 : Distributed SMB/CIFS Server Management Utility
4 : Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
5 : Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
6 : Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
7 : Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
8 : Copyright (C) 2008 Kai Blin (kai@samba.org)
9 :
10 : Originally written by Steve and Jim. Largely rewritten by tridge in
11 : November 2001.
12 :
13 : Reworked again by abartlet in December 2001
14 :
15 : Another overhaul, moving functionality into plug-ins loaded on demand by Kai
16 : in May 2008.
17 :
18 : This program is free software; you can redistribute it and/or modify
19 : it under the terms of the GNU General Public License as published by
20 : the Free Software Foundation; either version 3 of the License, or
21 : (at your option) any later version.
22 :
23 : This program is distributed in the hope that it will be useful,
24 : but WITHOUT ANY WARRANTY; without even the implied warranty of
25 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 : GNU General Public License for more details.
27 :
28 : You should have received a copy of the GNU General Public License
29 : along with this program. If not, see <http://www.gnu.org/licenses/>. */
30 :
31 : /*****************************************************/
32 : /* */
33 : /* Distributed SMB/CIFS Server Management Utility */
34 : /* */
35 : /* The intent was to make the syntax similar */
36 : /* to the NET utility (first developed in DOS */
37 : /* with additional interesting & useful functions */
38 : /* added in later SMB server network operating */
39 : /* systems). */
40 : /* */
41 : /*****************************************************/
42 :
43 : #include "includes.h"
44 : #include "lib/cmdline/cmdline.h"
45 : #include "utils/net.h"
46 : #include "secrets.h"
47 : #include "lib/netapi/netapi.h"
48 : #include "../libcli/security/security.h"
49 : #include "passdb.h"
50 : #include "messages.h"
51 : #include "cmdline_contexts.h"
52 : #include "lib/gencache.h"
53 : #include "auth/credentials/credentials.h"
54 : #include "source3/utils/passwd_proto.h"
55 : #include "auth/gensec/gensec.h"
56 :
57 : #ifdef WITH_FAKE_KASERVER
58 : #include "utils/net_afs.h"
59 : #endif
60 :
61 : /***********************************************************************/
62 : /* end of internationalization section */
63 : /***********************************************************************/
64 :
65 16 : enum netr_SchannelType get_sec_channel_type(const char *param)
66 : {
67 16 : if (!(param && *param)) {
68 10 : return get_default_sec_channel();
69 : } else {
70 6 : if (strequal(param, "PDC")) {
71 0 : return SEC_CHAN_BDC;
72 6 : } else if (strequal(param, "BDC")) {
73 0 : return SEC_CHAN_BDC;
74 6 : } else if (strequal(param, "MEMBER")) {
75 0 : return SEC_CHAN_WKSTA;
76 : #if 0
77 : } else if (strequal(param, "DOMAIN")) {
78 : return SEC_CHAN_DOMAIN;
79 : #endif
80 : } else {
81 6 : return get_default_sec_channel();
82 : }
83 : }
84 : }
85 :
86 0 : static int net_changetrustpw(struct net_context *c, int argc, const char **argv)
87 : {
88 0 : if (net_ads_check_our_domain(c) == 0)
89 0 : return net_ads_changetrustpw(c, argc, argv);
90 :
91 0 : return net_rpc_changetrustpw(c, argc, argv);
92 : }
93 :
94 0 : static void set_line_buffering(FILE *f)
95 : {
96 0 : setvbuf(f, NULL, _IOLBF, 0);
97 0 : }
98 :
99 3 : static int net_primarytrust_dumpinfo(struct net_context *c, int argc,
100 : const char **argv)
101 : {
102 3 : int role = lp_server_role();
103 3 : const char *domain = lp_workgroup();
104 3 : struct secrets_domain_info1 *info = NULL;
105 3 : bool include_secrets = c->opt_force;
106 3 : char *str = NULL;
107 : NTSTATUS status;
108 :
109 3 : if (role >= ROLE_ACTIVE_DIRECTORY_DC) {
110 0 : d_printf(_("net primarytrust dumpinfo is only supported "
111 : "on a DOMAIN_MEMBER for now.\n"));
112 0 : return 1;
113 : }
114 :
115 3 : if (c->opt_stdin) {
116 0 : set_line_buffering(stdin);
117 0 : set_line_buffering(stdout);
118 0 : set_line_buffering(stderr);
119 : }
120 :
121 3 : status = secrets_fetch_or_upgrade_domain_info(domain,
122 : talloc_tos(),
123 : &info);
124 3 : if (!NT_STATUS_IS_OK(status)) {
125 0 : d_fprintf(stderr,
126 0 : _("Unable to fetch the information for domain[%s] "
127 : "in the secrets database.\n"),
128 : domain);
129 0 : return 1;
130 : }
131 :
132 3 : str = secrets_domain_info_string(info, info, domain, include_secrets);
133 3 : if (str == NULL) {
134 0 : d_fprintf(stderr, "secrets_domain_info_string() failed.\n");
135 0 : return 1;
136 : }
137 :
138 3 : d_printf("%s", str);
139 3 : if (!c->opt_force) {
140 3 : d_printf(_("The password values are only included using "
141 : "-f flag.\n"));
142 : }
143 :
144 3 : TALLOC_FREE(info);
145 3 : return 0;
146 : }
147 :
148 : /**
149 : * Entrypoint for 'net primarytrust' code.
150 : *
151 : * @param argc Standard argc.
152 : * @param argv Standard argv without initial components.
153 : *
154 : * @return Integer status (0 means success).
155 : */
156 :
157 3 : static int net_primarytrust(struct net_context *c, int argc, const char **argv)
158 : {
159 3 : struct functable func[] = {
160 : {
161 : .funcname = "dumpinfo",
162 : .fn = net_primarytrust_dumpinfo,
163 : .valid_transports = NET_TRANSPORT_LOCAL,
164 : .description = N_("Dump the details of the "
165 : "workstation trust"),
166 : .usage = N_(" net [options] primarytrust "
167 : "dumpinfo'\n"
168 : " Dump the details of the "
169 : "workstation trust in "
170 : "secrets.tdb.\n"
171 : " Requires the -f flag to "
172 : "include the password values."),
173 : },
174 : {
175 : .funcname = NULL,
176 : },
177 : };
178 :
179 3 : return net_run_function(c, argc, argv, "net primarytrust", func);
180 : }
181 :
182 0 : static int net_changesecretpw(struct net_context *c, int argc,
183 : const char **argv)
184 : {
185 : char *trust_pw;
186 0 : int role = lp_server_role();
187 :
188 0 : if (role != ROLE_DOMAIN_MEMBER) {
189 0 : d_printf(_("Machine account password change only supported on a DOMAIN_MEMBER.\n"
190 : "Do NOT use this function unless you know what it does!\n"
191 : "This function will change the ADS Domain member "
192 : "machine account password in the secrets.tdb file!\n"));
193 0 : return 1;
194 : }
195 :
196 0 : if(c->opt_force) {
197 0 : struct secrets_domain_info1 *info = NULL;
198 0 : struct secrets_domain_info1_change *prev = NULL;
199 : NTSTATUS status;
200 0 : struct timeval tv = timeval_current();
201 0 : NTTIME now = timeval_to_nttime(&tv);
202 :
203 0 : if (c->opt_stdin) {
204 0 : set_line_buffering(stdin);
205 0 : set_line_buffering(stdout);
206 0 : set_line_buffering(stderr);
207 : }
208 :
209 0 : trust_pw = get_pass(_("Enter machine password: "), c->opt_stdin);
210 0 : if (trust_pw == NULL) {
211 0 : d_fprintf(stderr,
212 0 : _("Error in reading machine password\n"));
213 0 : return 1;
214 : }
215 :
216 0 : status = secrets_prepare_password_change(lp_workgroup(),
217 : "localhost",
218 : trust_pw,
219 : talloc_tos(),
220 : &info, &prev);
221 0 : if (!NT_STATUS_IS_OK(status)) {
222 0 : d_fprintf(stderr,
223 0 : _("Unable to write the machine account password in the secrets database"));
224 0 : return 1;
225 : }
226 0 : if (prev != NULL) {
227 0 : d_fprintf(stderr,
228 0 : _("Pending machine account password change found - aborting."));
229 0 : status = secrets_failed_password_change("localhost",
230 0 : NT_STATUS_REQUEST_NOT_ACCEPTED,
231 0 : NT_STATUS_NOT_COMMITTED,
232 : info);
233 0 : if (!NT_STATUS_IS_OK(status)) {
234 0 : d_fprintf(stderr,
235 0 : _("Failed to abort machine account password change"));
236 : }
237 0 : return 1;
238 : }
239 0 : status = secrets_finish_password_change("localhost", now, info);
240 0 : if (!NT_STATUS_IS_OK(status)) {
241 0 : d_fprintf(stderr,
242 0 : _("Unable to write the machine account password in the secrets database"));
243 0 : return 1;
244 : }
245 :
246 0 : d_printf(_("Modified trust account password in secrets database\n"));
247 : }
248 : else {
249 0 : d_printf(_("Machine account password change requires the -f flag.\n"
250 : "Do NOT use this function unless you know what it does!\n"
251 : "This function will change the ADS Domain member "
252 : "machine account password in the secrets.tdb file!\n"));
253 : }
254 :
255 0 : return 0;
256 : }
257 :
258 : /**
259 : * @brief Set the authorised user for winbindd access in secrets.tdb
260 : */
261 0 : static int net_setauthuser(struct net_context *c, int argc, const char **argv)
262 : {
263 0 : const char *password = NULL;
264 : bool ok;
265 :
266 0 : if (!secrets_init()) {
267 0 : d_fprintf(stderr, _("Failed to open secrets.tdb.\n"));
268 0 : return 1;
269 : }
270 :
271 : /* Delete the settings. */
272 0 : if (argc >= 1) {
273 0 : if (strncmp(argv[0], "delete", 6) != 0) {
274 0 : d_fprintf(stderr,_("Usage:\n"));
275 0 : d_fprintf(stderr,
276 0 : _(" net setauthuser -U user[%%password] \n"
277 : " Set the auth user account to user"
278 : "password. Prompt for password if not "
279 : "specified.\n"));
280 0 : d_fprintf(stderr,
281 0 : _(" net setauthuser delete\n"
282 : " Delete the auth user setting.\n"));
283 0 : return 1;
284 : }
285 0 : secrets_delete_entry(SECRETS_AUTH_USER);
286 0 : secrets_delete_entry(SECRETS_AUTH_DOMAIN);
287 0 : secrets_delete_entry(SECRETS_AUTH_PASSWORD);
288 0 : return 0;
289 : }
290 :
291 0 : if (!c->opt_user_specified) {
292 0 : d_fprintf(stderr, _("Usage:\n"));
293 0 : d_fprintf(stderr,
294 0 : _(" net setauthuser -U user[%%password]\n"
295 : " Set the auth user account to user"
296 : "password. Prompt for password if not "
297 : "specified.\n"));
298 0 : d_fprintf(stderr,
299 0 : _(" net setauthuser delete\n"
300 : " Delete the auth user setting.\n"));
301 0 : return 1;
302 : }
303 :
304 0 : password = net_prompt_pass(c, _("the auth user"));
305 0 : if (password == NULL) {
306 0 : d_fprintf(stderr,_("Failed to get the auth users password.\n"));
307 0 : return 1;
308 : }
309 :
310 0 : ok = secrets_store_creds(c->creds);
311 0 : if (!ok) {
312 0 : d_fprintf(stderr, _("Failed storing auth user credentials\n"));
313 0 : return 1;
314 : }
315 :
316 0 : return 0;
317 : }
318 :
319 : /**
320 : * @brief Get the auth user settings
321 : */
322 0 : static int net_getauthuser(struct net_context *c, int argc, const char **argv)
323 : {
324 : char *user, *domain, *password;
325 :
326 : /* Lift data from secrets file */
327 :
328 0 : secrets_fetch_ipc_userpass(&user, &domain, &password);
329 :
330 0 : if ((!user || !*user) && (!domain || !*domain ) &&
331 0 : (!password || !*password)){
332 :
333 0 : SAFE_FREE(user);
334 0 : SAFE_FREE(domain);
335 0 : SAFE_FREE(password);
336 0 : d_printf(_("No authorised user configured\n"));
337 0 : return 0;
338 : }
339 :
340 : /* Pretty print authorised user info */
341 :
342 0 : d_printf("%s%s%s%s%s\n", domain ? domain : "",
343 0 : domain ? lp_winbind_separator(): "", user,
344 0 : password ? "%" : "", password ? password : "");
345 :
346 0 : SAFE_FREE(user);
347 0 : SAFE_FREE(domain);
348 0 : SAFE_FREE(password);
349 :
350 0 : return 0;
351 : }
352 : /*
353 : Retrieve our local SID or the SID for the specified name
354 : */
355 3 : static int net_getlocalsid(struct net_context *c, int argc, const char **argv)
356 : {
357 : struct dom_sid sid;
358 : const char *name;
359 : struct dom_sid_buf sid_str;
360 :
361 3 : if (argc >= 1) {
362 3 : name = argv[0];
363 : }
364 : else {
365 0 : name = lp_netbios_name();
366 : }
367 :
368 3 : if(!initialize_password_db(false, NULL)) {
369 0 : d_fprintf(stderr, _("WARNING: Could not open passdb\n"));
370 0 : return 1;
371 : }
372 :
373 : /* first check to see if we can even access secrets, so we don't
374 : panic when we can't. */
375 :
376 3 : if (!secrets_init()) {
377 0 : d_fprintf(stderr,
378 0 : _("Unable to open secrets.tdb. Can't fetch domain "
379 : "SID for name: %s\n"), name);
380 0 : return 1;
381 : }
382 :
383 : /* Generate one, if it doesn't exist */
384 3 : get_global_sam_sid();
385 :
386 3 : if (!secrets_fetch_domain_sid(name, &sid)) {
387 0 : DEBUG(0, ("Can't fetch domain SID for name: %s\n", name));
388 0 : return 1;
389 : }
390 3 : d_printf(_("SID for domain %s is: %s\n"),
391 : name,
392 : dom_sid_str_buf(&sid, &sid_str));
393 3 : return 0;
394 : }
395 :
396 39 : static int net_setlocalsid(struct net_context *c, int argc, const char **argv)
397 : {
398 : struct dom_sid sid;
399 :
400 39 : if ( (argc != 1)
401 39 : || (strncmp(argv[0], "S-1-5-21-", strlen("S-1-5-21-")) != 0)
402 39 : || (!string_to_sid(&sid, argv[0]))
403 39 : || (sid.num_auths != 4)) {
404 0 : d_printf(_("Usage:"));
405 0 : d_printf(" net setlocalsid S-1-5-21-x-y-z\n");
406 0 : return 1;
407 : }
408 :
409 39 : if (!secrets_store_domain_sid(lp_netbios_name(), &sid)) {
410 0 : DEBUG(0,("Can't store domain SID as a pdc/bdc.\n"));
411 0 : return 1;
412 : }
413 :
414 39 : return 0;
415 : }
416 :
417 0 : static int net_setdomainsid(struct net_context *c, int argc, const char **argv)
418 : {
419 : struct dom_sid sid;
420 :
421 0 : if ( (argc != 1)
422 0 : || (strncmp(argv[0], "S-1-5-21-", strlen("S-1-5-21-")) != 0)
423 0 : || (!string_to_sid(&sid, argv[0]))
424 0 : || (sid.num_auths != 4)) {
425 0 : d_printf(_("Usage:"));
426 0 : d_printf(" net setdomainsid S-1-5-21-x-y-z\n");
427 0 : return 1;
428 : }
429 :
430 0 : if (!secrets_store_domain_sid(lp_workgroup(), &sid)) {
431 0 : DEBUG(0,("Can't store domain SID.\n"));
432 0 : return 1;
433 : }
434 :
435 0 : return 0;
436 : }
437 :
438 2 : static int net_getdomainsid(struct net_context *c, int argc, const char **argv)
439 : {
440 : struct dom_sid domain_sid;
441 : struct dom_sid_buf sid_str;
442 :
443 2 : if (argc > 0) {
444 0 : d_printf(_("Usage:"));
445 0 : d_printf(" net getdomainsid\n");
446 0 : return 1;
447 : }
448 :
449 2 : if(!initialize_password_db(false, NULL)) {
450 0 : d_fprintf(stderr, _("WARNING: Could not open passdb\n"));
451 0 : return 1;
452 : }
453 :
454 : /* first check to see if we can even access secrets, so we don't
455 : panic when we can't. */
456 :
457 2 : if (!secrets_init()) {
458 0 : d_fprintf(stderr, _("Unable to open secrets.tdb. Can't fetch "
459 : "domain SID for name: %s\n"),
460 : get_global_sam_name());
461 0 : return 1;
462 : }
463 :
464 : /* Generate one, if it doesn't exist */
465 2 : get_global_sam_sid();
466 :
467 2 : if (!IS_DC) {
468 0 : if (!secrets_fetch_domain_sid(lp_netbios_name(), &domain_sid)) {
469 0 : d_fprintf(stderr, _("Could not fetch local SID\n"));
470 0 : return 1;
471 : }
472 0 : d_printf(_("SID for local machine %s is: %s\n"),
473 : lp_netbios_name(),
474 : dom_sid_str_buf(&domain_sid, &sid_str));
475 : }
476 2 : if (!secrets_fetch_domain_sid(c->opt_workgroup, &domain_sid)) {
477 0 : d_fprintf(stderr, _("Could not fetch domain SID\n"));
478 0 : return 1;
479 : }
480 :
481 2 : d_printf(_("SID for domain %s is: %s\n"),
482 : c->opt_workgroup,
483 : dom_sid_str_buf(&domain_sid, &sid_str));
484 :
485 2 : return 0;
486 : }
487 :
488 0 : static bool search_maxrid(struct pdb_search *search, const char *type,
489 : uint32_t *max_rid)
490 : {
491 : struct samr_displayentry *entries;
492 : uint32_t i, num_entries;
493 :
494 0 : if (search == NULL) {
495 0 : d_fprintf(stderr, _("get_maxrid: Could not search %s\n"), type);
496 0 : return false;
497 : }
498 :
499 0 : num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries);
500 0 : for (i=0; i<num_entries; i++)
501 0 : *max_rid = MAX(*max_rid, entries[i].rid);
502 0 : TALLOC_FREE(search);
503 0 : return true;
504 : }
505 :
506 0 : static uint32_t get_maxrid(void)
507 : {
508 0 : uint32_t max_rid = 0;
509 :
510 0 : if (!search_maxrid(pdb_search_users(talloc_tos(), 0), "users", &max_rid))
511 0 : return 0;
512 :
513 0 : if (!search_maxrid(pdb_search_groups(talloc_tos()), "groups", &max_rid))
514 0 : return 0;
515 :
516 0 : if (!search_maxrid(pdb_search_aliases(talloc_tos(),
517 0 : get_global_sam_sid()),
518 : "aliases", &max_rid))
519 0 : return 0;
520 :
521 0 : return max_rid;
522 : }
523 :
524 0 : static int net_maxrid(struct net_context *c, int argc, const char **argv)
525 : {
526 : uint32_t rid;
527 :
528 0 : if (argc != 0) {
529 0 : d_fprintf(stderr, "%s net maxrid\n", _("Usage:"));
530 0 : return 1;
531 : }
532 :
533 0 : if ((rid = get_maxrid()) == 0) {
534 0 : d_fprintf(stderr, _("can't get current maximum rid\n"));
535 0 : return 1;
536 : }
537 :
538 0 : d_printf(_("Currently used maximum rid: %d\n"), rid);
539 :
540 0 : return 0;
541 : }
542 :
543 : /* main function table */
544 : static struct functable net_func[] = {
545 : {
546 : "rpc",
547 : net_rpc,
548 : NET_TRANSPORT_RPC,
549 : N_("Run functions using RPC transport"),
550 : N_(" Use 'net help rpc' to get more extensive information "
551 : "about 'net rpc' commands.")
552 : },
553 : {
554 : "rap",
555 : net_rap,
556 : NET_TRANSPORT_RAP,
557 : N_("Run functions using RAP transport"),
558 : N_(" Use 'net help rap' to get more extensive information "
559 : "about 'net rap' commands.")
560 : },
561 : {
562 : "ads",
563 : net_ads,
564 : NET_TRANSPORT_ADS,
565 : N_("Run functions using ADS transport"),
566 : N_(" Use 'net help ads' to get more extensive information "
567 : "about 'net ads' commands.")
568 : },
569 :
570 : /* eventually these should auto-choose the transport ... */
571 : {
572 : "file",
573 : net_file,
574 : NET_TRANSPORT_RPC | NET_TRANSPORT_RAP,
575 : N_("Functions on remote opened files"),
576 : N_(" Use 'net help file' to get more information about 'net "
577 : "file' commands.")
578 : },
579 : {
580 : "share",
581 : net_share,
582 : NET_TRANSPORT_RPC | NET_TRANSPORT_RAP,
583 : N_("Functions on shares"),
584 : N_(" Use 'net help share' to get more information about 'net "
585 : "share' commands.")
586 : },
587 : {
588 : "session",
589 : net_rap_session,
590 : NET_TRANSPORT_RAP,
591 : N_("Manage sessions"),
592 : N_(" Use 'net help session' to get more information about "
593 : "'net session' commands.")
594 : },
595 : {
596 : "server",
597 : net_rap_server,
598 : NET_TRANSPORT_RAP,
599 : N_("List servers in workgroup"),
600 : N_(" Use 'net help server' to get more information about 'net "
601 : "server' commands.")
602 : },
603 : {
604 : "domain",
605 : net_rap_domain,
606 : NET_TRANSPORT_RAP,
607 : N_("List domains/workgroups on network"),
608 : N_(" Use 'net help domain' to get more information about 'net "
609 : "domain' commands.")
610 : },
611 : {
612 : "printq",
613 : net_rap_printq,
614 : NET_TRANSPORT_RAP,
615 : N_("Modify printer queue"),
616 : N_(" Use 'net help printq' to get more information about 'net "
617 : "printq' commands.")
618 : },
619 : {
620 : "user",
621 : net_user,
622 : NET_TRANSPORT_ADS | NET_TRANSPORT_RPC | NET_TRANSPORT_RAP,
623 : N_("Manage users"),
624 : N_(" Use 'net help user' to get more information about 'net "
625 : "user' commands.")
626 : },
627 : {
628 : "group",
629 : net_group,
630 : NET_TRANSPORT_ADS | NET_TRANSPORT_RPC | NET_TRANSPORT_RAP,
631 : N_("Manage groups"),
632 : N_(" Use 'net help group' to get more information about 'net "
633 : "group' commands.")
634 : },
635 : {
636 : "groupmap",
637 : net_groupmap,
638 : NET_TRANSPORT_LOCAL,
639 : N_("Manage group mappings"),
640 : N_(" Use 'net help groupmap' to get more information about "
641 : "'net groupmap' commands.")
642 : },
643 : {
644 : "sam",
645 : net_sam,
646 : NET_TRANSPORT_LOCAL,
647 : N_("Functions on the SAM database"),
648 : N_(" Use 'net help sam' to get more information about 'net "
649 : "sam' commands.")
650 : },
651 : {
652 : "validate",
653 : net_rap_validate,
654 : NET_TRANSPORT_RAP,
655 : N_("Validate username and password"),
656 : N_(" Use 'net help validate' to get more information about "
657 : "'net validate' commands.")
658 : },
659 : {
660 : "groupmember",
661 : net_rap_groupmember,
662 : NET_TRANSPORT_RAP,
663 : N_("Modify group memberships"),
664 : N_(" Use 'net help groupmember' to get more information about "
665 : "'net groupmember' commands.")
666 : },
667 : { "admin",
668 : net_rap_admin,
669 : NET_TRANSPORT_RAP,
670 : N_("Execute remote command on a remote OS/2 server"),
671 : N_(" Use 'net help admin' to get more information about 'net "
672 : "admin' commands.")
673 : },
674 : { "service",
675 : net_rap_service,
676 : NET_TRANSPORT_RAP,
677 : N_("List/modify running services"),
678 : N_(" Use 'net help service' to get more information about "
679 : "'net service' commands.")
680 : },
681 : {
682 : "password",
683 : net_rap_password,
684 : NET_TRANSPORT_RAP,
685 : N_("Change user password on target server"),
686 : N_(" Use 'net help password' to get more information about "
687 : "'net password' commands.")
688 : },
689 : {
690 : "primarytrust",
691 : net_primarytrust,
692 : NET_TRANSPORT_RPC,
693 : N_("Run functions related to the primary workstation trust."),
694 : N_(" Use 'net help primarytrust' to get more extensive information "
695 : "about 'net primarytrust' commands.")
696 : },
697 : { "changetrustpw",
698 : net_changetrustpw,
699 : NET_TRANSPORT_ADS | NET_TRANSPORT_RPC,
700 : N_("Change the trust password"),
701 : N_(" Use 'net help changetrustpw' to get more information "
702 : "about 'net changetrustpw'.")
703 : },
704 : { "changesecretpw",
705 : net_changesecretpw,
706 : NET_TRANSPORT_LOCAL,
707 : N_("Change the secret password"),
708 : N_(" net [options] changesecretpw\n"
709 : " Change the ADS domain member machine account password "
710 : "in secrets.tdb.\n"
711 : " Do NOT use this function unless you know what it does.\n"
712 : " Requires the -f flag to work.")
713 : },
714 : {
715 : "setauthuser",
716 : net_setauthuser,
717 : NET_TRANSPORT_LOCAL,
718 : N_("Set the winbind auth user"),
719 : N_(" net -U user[%%password] [-W domain] setauthuser\n"
720 : " Set the auth user, password (and optionally domain\n"
721 : " Will prompt for password if not given.\n"
722 : " net setauthuser delete\n"
723 : " Delete the existing auth user settings.")
724 : },
725 : {
726 : "getauthuser",
727 : net_getauthuser,
728 : NET_TRANSPORT_LOCAL,
729 : N_("Get the winbind auth user settings"),
730 : N_(" net getauthuser\n"
731 : " Get the current winbind auth user settings.")
732 : },
733 : { "time",
734 : net_time,
735 : NET_TRANSPORT_LOCAL,
736 : N_("Show/set time"),
737 : N_(" Use 'net help time' to get more information about 'net "
738 : "time' commands.")
739 : },
740 : { "lookup",
741 : net_lookup,
742 : NET_TRANSPORT_LOCAL,
743 : N_("Look up host names/IP addresses"),
744 : N_(" Use 'net help lookup' to get more information about 'net "
745 : "lookup' commands.")
746 : },
747 : { "g_lock",
748 : net_g_lock,
749 : NET_TRANSPORT_LOCAL,
750 : N_("Manipulate the global lock table"),
751 : N_(" Use 'net help g_lock' to get more information about "
752 : "'net g_lock' commands.")
753 : },
754 : { "join",
755 : net_join,
756 : NET_TRANSPORT_ADS | NET_TRANSPORT_RPC,
757 : N_("Join a domain/AD"),
758 : N_(" Use 'net help join' to get more information about 'net "
759 : "join'.")
760 : },
761 : { "offlinejoin",
762 : net_offlinejoin,
763 : NET_TRANSPORT_ADS | NET_TRANSPORT_RPC,
764 : N_("Perform offline domain join"),
765 : N_(" Use 'net help offlinejoin' to get more information about 'net "
766 : "offlinejoin'.")
767 : },
768 : { "dom",
769 : net_dom,
770 : NET_TRANSPORT_LOCAL,
771 : N_("Join/unjoin (remote) machines to/from a domain/AD"),
772 : N_(" Use 'net help dom' to get more information about 'net "
773 : "dom' commands.")
774 : },
775 : { "cache",
776 : net_cache,
777 : NET_TRANSPORT_LOCAL,
778 : N_("Operate on the cache tdb file"),
779 : N_(" Use 'net help cache' to get more information about 'net "
780 : "cache' commands.")
781 : },
782 : { "getlocalsid",
783 : net_getlocalsid,
784 : NET_TRANSPORT_LOCAL,
785 : N_("Get the SID for the local domain"),
786 : N_(" net getlocalsid")
787 : },
788 : { "setlocalsid",
789 : net_setlocalsid,
790 : NET_TRANSPORT_LOCAL,
791 : N_("Set the SID for the local domain"),
792 : N_(" net setlocalsid S-1-5-21-x-y-z")
793 : },
794 : { "setdomainsid",
795 : net_setdomainsid,
796 : NET_TRANSPORT_LOCAL,
797 : N_("Set domain SID on member servers"),
798 : N_(" net setdomainsid S-1-5-21-x-y-z")
799 : },
800 : { "getdomainsid",
801 : net_getdomainsid,
802 : NET_TRANSPORT_LOCAL,
803 : N_("Get domain SID on member servers"),
804 : N_(" net getdomainsid")
805 : },
806 : { "maxrid",
807 : net_maxrid,
808 : NET_TRANSPORT_LOCAL,
809 : N_("Display the maximum RID currently used"),
810 : N_(" net maxrid")
811 : },
812 : { "idmap",
813 : net_idmap,
814 : NET_TRANSPORT_LOCAL,
815 : N_("IDmap functions"),
816 : N_(" Use 'net help idmap to get more information about 'net "
817 : "idmap' commands.")
818 : },
819 : { "status",
820 : net_status,
821 : NET_TRANSPORT_LOCAL,
822 : N_("Display server status"),
823 : N_(" Use 'net help status' to get more information about 'net "
824 : "status' commands.")
825 : },
826 : { "usershare",
827 : net_usershare,
828 : NET_TRANSPORT_LOCAL,
829 : N_("Manage user-modifiable shares"),
830 : N_(" Use 'net help usershare to get more information about "
831 : "'net usershare' commands.")
832 : },
833 : { "usersidlist",
834 : net_usersidlist,
835 : NET_TRANSPORT_RPC,
836 : N_("Display list of all users with SID"),
837 : N_(" Use 'net help usersidlist' to get more information about "
838 : "'net usersidlist'.")
839 : },
840 : { "conf",
841 : net_conf,
842 : NET_TRANSPORT_LOCAL,
843 : N_("Manage Samba registry based configuration"),
844 : N_(" Use 'net help conf' to get more information about 'net "
845 : "conf' commands.")
846 : },
847 : { "registry",
848 : net_registry,
849 : NET_TRANSPORT_LOCAL,
850 : N_("Manage the Samba registry"),
851 : N_(" Use 'net help registry' to get more information about "
852 : "'net registry' commands.")
853 : },
854 : { "eventlog",
855 : net_eventlog,
856 : NET_TRANSPORT_LOCAL,
857 : N_("Process Win32 *.evt eventlog files"),
858 : N_(" Use 'net help eventlog' to get more information about "
859 : "'net eventlog' commands.")
860 : },
861 : { "printing",
862 : net_printing,
863 : NET_TRANSPORT_LOCAL,
864 : N_("Process tdb printer files"),
865 : N_(" Use 'net help printing' to get more information about "
866 : "'net printing' commands.")
867 : },
868 :
869 : { "serverid",
870 : net_serverid,
871 : NET_TRANSPORT_LOCAL,
872 : N_("Manage the serverid tdb"),
873 : N_(" Use 'net help serverid' to get more information about "
874 : "'net serverid' commands.")
875 : },
876 :
877 : { "notify",
878 : net_notify,
879 : NET_TRANSPORT_LOCAL,
880 : N_("notifyd client code"),
881 : N_(" Use 'net help notify' to get more information about "
882 : "'net notify' commands.")
883 : },
884 :
885 : { "tdb",
886 : net_tdb,
887 : NET_TRANSPORT_LOCAL,
888 : N_("Show information from tdb records"),
889 : N_(" Use 'net help tdb' to get more information about "
890 : "'net tdb' commands.")
891 : },
892 :
893 : { "vfs",
894 : net_vfs,
895 : NET_TRANSPORT_LOCAL,
896 : N_("Filesystem operation through the VFS stack"),
897 : N_(" Use 'net help vfs' to get more information about "
898 : "'net vfs' commands.")
899 : },
900 :
901 : #ifdef WITH_FAKE_KASERVER
902 : { "afs",
903 : net_afs,
904 : NET_TRANSPORT_LOCAL,
905 : N_("Manage AFS tokens"),
906 : N_(" Use 'net help afs' to get more information about 'net "
907 : "afs' commands.")
908 : },
909 : #endif
910 :
911 : { "help",
912 : net_help,
913 : NET_TRANSPORT_LOCAL,
914 : N_("Print usage information"),
915 : N_(" Use 'net help help' to list usage information for 'net' "
916 : "commands.")
917 : },
918 : {NULL, NULL, 0, NULL, NULL}
919 : };
920 :
921 :
922 : /****************************************************************************
923 : main program
924 : ****************************************************************************/
925 3256 : int main(int argc, char **argv)
926 : {
927 : int opt,i;
928 3256 : int rc = 0;
929 3256 : int argc_new = 0;
930 : const char ** argv_new;
931 3256 : const char **argv_const = discard_const_p(const char *, argv);
932 : poptContext pc;
933 3256 : TALLOC_CTX *frame = talloc_stackframe();
934 3256 : struct net_context *c = talloc_zero(frame, struct net_context);
935 : bool ok;
936 :
937 139084 : struct poptOption long_options[] = {
938 : {
939 : .longName = "help",
940 : .shortName = 'h',
941 : .argInfo = POPT_ARG_NONE,
942 : .val = 'h',
943 : },
944 : {
945 : .longName = "target-workgroup",
946 : .shortName = 'w',
947 : .argInfo = POPT_ARG_STRING,
948 3256 : .arg = &c->opt_target_workgroup,
949 : },
950 : {
951 : .longName = "ipaddress",
952 : .shortName = 'I',
953 : .argInfo = POPT_ARG_STRING,
954 : .arg = 0,
955 : .val = 'I',
956 : },
957 : {
958 : .longName = "port",
959 : .shortName = 'p',
960 : .argInfo = POPT_ARG_INT,
961 3256 : .arg = &c->opt_port,
962 : },
963 : {
964 : .longName = "myname",
965 : .shortName = 0,
966 : .argInfo = POPT_ARG_STRING,
967 3256 : .arg = &c->opt_requester_name,
968 : },
969 : {
970 : .longName = "server",
971 : .shortName = 'S',
972 : .argInfo = POPT_ARG_STRING,
973 3256 : .arg = &c->opt_host,
974 : },
975 : {
976 : .longName = "container",
977 : .shortName = 'c',
978 : .argInfo = POPT_ARG_STRING,
979 3256 : .arg = &c->opt_container,
980 : },
981 : {
982 : .longName = "comment",
983 : .shortName = 'C',
984 : .argInfo = POPT_ARG_STRING,
985 3256 : .arg = &c->opt_comment,
986 : },
987 : {
988 : .longName = "maxusers",
989 : .shortName = 'M',
990 : .argInfo = POPT_ARG_INT,
991 3256 : .arg = &c->opt_maxusers,
992 : },
993 : {
994 : .longName = "flags",
995 : .shortName = 'F',
996 : .argInfo = POPT_ARG_INT,
997 3256 : .arg = &c->opt_flags,
998 : },
999 : {
1000 : .longName = "long",
1001 : .argInfo = POPT_ARG_NONE,
1002 3256 : .arg = &c->opt_long_list_entries,
1003 : },
1004 : {
1005 : .longName = "reboot",
1006 : .shortName = 'r',
1007 : .argInfo = POPT_ARG_NONE,
1008 3256 : .arg = &c->opt_reboot,
1009 : },
1010 : {
1011 : .longName = "force",
1012 : .shortName = 'f',
1013 : .argInfo = POPT_ARG_NONE,
1014 3256 : .arg = &c->opt_force,
1015 : },
1016 : {
1017 : .longName = "stdin",
1018 : .shortName = 'i',
1019 : .argInfo = POPT_ARG_NONE,
1020 3256 : .arg = &c->opt_stdin,
1021 : },
1022 : {
1023 : .longName = "timeout",
1024 : .shortName = 't',
1025 : .argInfo = POPT_ARG_INT,
1026 3256 : .arg = &c->opt_timeout,
1027 : },
1028 : {
1029 : .longName = "request-timeout",
1030 : .shortName = 0,
1031 : .argInfo = POPT_ARG_INT,
1032 3256 : .arg = &c->opt_request_timeout,
1033 : },
1034 : {
1035 : .longName = "use-ccache",
1036 : .shortName = 0,
1037 : .argInfo = POPT_ARG_NONE,
1038 3256 : .arg = &c->opt_ccache,
1039 : },
1040 : {
1041 : .longName = "verbose",
1042 : .shortName = 'v',
1043 : .argInfo = POPT_ARG_NONE,
1044 3256 : .arg = &c->opt_verbose,
1045 : },
1046 : {
1047 : .longName = "test",
1048 : .shortName = 'T',
1049 : .argInfo = POPT_ARG_NONE,
1050 3256 : .arg = &c->opt_testmode,
1051 : },
1052 : /* Options for 'net groupmap set' */
1053 : {
1054 : .longName = "local",
1055 : .shortName = 'L',
1056 : .argInfo = POPT_ARG_NONE,
1057 3256 : .arg = &c->opt_localgroup,
1058 : },
1059 : {
1060 : .longName = "domain",
1061 : .shortName = 'D',
1062 : .argInfo = POPT_ARG_NONE,
1063 3256 : .arg = &c->opt_domaingroup,
1064 : },
1065 : {
1066 : .longName = "ntname",
1067 : .shortName = 0,
1068 : .argInfo = POPT_ARG_STRING,
1069 3256 : .arg = &c->opt_newntname,
1070 : },
1071 : {
1072 : .longName = "rid",
1073 : .shortName = 0,
1074 : .argInfo = POPT_ARG_INT,
1075 3256 : .arg = &c->opt_rid,
1076 : },
1077 : /* Options for 'net rpc share migrate' */
1078 : {
1079 : .longName = "acls",
1080 : .shortName = 0,
1081 : .argInfo = POPT_ARG_NONE,
1082 3256 : .arg = &c->opt_acls,
1083 : },
1084 : {
1085 : .longName = "attrs",
1086 : .shortName = 0,
1087 : .argInfo = POPT_ARG_NONE,
1088 3256 : .arg = &c->opt_attrs,
1089 : },
1090 : {
1091 : .longName = "timestamps",
1092 : .shortName = 0,
1093 : .argInfo = POPT_ARG_NONE,
1094 3256 : .arg = &c->opt_timestamps,
1095 : },
1096 : {
1097 : .longName = "exclude",
1098 : .shortName = 'X',
1099 : .argInfo = POPT_ARG_STRING,
1100 3256 : .arg = &c->opt_exclude,
1101 : },
1102 : {
1103 : .longName = "destination",
1104 : .shortName = 0,
1105 : .argInfo = POPT_ARG_STRING,
1106 3256 : .arg = &c->opt_destination,
1107 : },
1108 : {
1109 : .longName = "tallocreport",
1110 : .shortName = 0,
1111 : .argInfo = POPT_ARG_NONE,
1112 3256 : .arg = &c->do_talloc_report,
1113 : },
1114 : /* Options for 'net rpc vampire (keytab)' */
1115 : {
1116 : .longName = "force-full-repl",
1117 : .shortName = 0,
1118 : .argInfo = POPT_ARG_NONE,
1119 3256 : .arg = &c->opt_force_full_repl,
1120 : },
1121 : {
1122 : .longName = "single-obj-repl",
1123 : .shortName = 0,
1124 : .argInfo = POPT_ARG_NONE,
1125 3256 : .arg = &c->opt_single_obj_repl,
1126 : },
1127 : {
1128 : .longName = "clean-old-entries",
1129 : .shortName = 0,
1130 : .argInfo = POPT_ARG_NONE,
1131 3256 : .arg = &c->opt_clean_old_entries,
1132 : },
1133 : /* Options for 'net idmap'*/
1134 : {
1135 : .longName = "db",
1136 : .shortName = 0,
1137 : .argInfo = POPT_ARG_STRING,
1138 3256 : .arg = &c->opt_db,
1139 : },
1140 : {
1141 : .longName = "lock",
1142 : .shortName = 0,
1143 : .argInfo = POPT_ARG_NONE,
1144 3256 : .arg = &c->opt_lock,
1145 : },
1146 : {
1147 : .longName = "auto",
1148 : .shortName = 'a',
1149 : .argInfo = POPT_ARG_NONE,
1150 3256 : .arg = &c->opt_auto,
1151 : },
1152 : {
1153 : .longName = "repair",
1154 : .shortName = 0,
1155 : .argInfo = POPT_ARG_NONE,
1156 3256 : .arg = &c->opt_repair,
1157 : },
1158 : /* Options for 'net registry check'*/
1159 : {
1160 : .longName = "reg-version",
1161 : .shortName = 0,
1162 : .argInfo = POPT_ARG_INT,
1163 3256 : .arg = &c->opt_reg_version,
1164 : },
1165 : {
1166 : .longName = "output",
1167 : .shortName = 'o',
1168 : .argInfo = POPT_ARG_STRING,
1169 3256 : .arg = &c->opt_output,
1170 : },
1171 : {
1172 : .longName = "wipe",
1173 : .shortName = 0,
1174 : .argInfo = POPT_ARG_NONE,
1175 3256 : .arg = &c->opt_wipe,
1176 : },
1177 : /* Options for 'net registry import' */
1178 : {
1179 : .longName = "precheck",
1180 : .shortName = 0,
1181 : .argInfo = POPT_ARG_STRING,
1182 3256 : .arg = &c->opt_precheck,
1183 : },
1184 : /* Options for 'net ads join or leave' */
1185 : {
1186 : .longName = "no-dns-updates",
1187 : .shortName = 0,
1188 : .argInfo = POPT_ARG_NONE,
1189 3256 : .arg = &c->opt_no_dns_updates,
1190 : },
1191 : {
1192 : .longName = "keep-account",
1193 : .shortName = 0,
1194 : .argInfo = POPT_ARG_NONE,
1195 3256 : .arg = &c->opt_keep_account,
1196 : },
1197 : {
1198 : .longName = "json",
1199 : .shortName = 0,
1200 : .argInfo = POPT_ARG_NONE,
1201 3256 : .arg = &c->opt_json,
1202 : },
1203 : /* Options for 'net vfs' */
1204 : {
1205 : .longName = "continue",
1206 : .argInfo = POPT_ARG_NONE,
1207 3256 : .arg = &c->opt_continue_on_error,
1208 : .descrip = "Continue on errors",
1209 : },
1210 : {
1211 : .longName = "recursive",
1212 : .argInfo = POPT_ARG_NONE,
1213 3256 : .arg = &c->opt_recursive,
1214 : .descrip = "Traverse directory hierarchy",
1215 : },
1216 : {
1217 : .longName = "follow-symlinks",
1218 : .argInfo = POPT_ARG_NONE,
1219 3256 : .arg = &c->opt_follow_symlink,
1220 : .descrip = "follow symlinks",
1221 : },
1222 3256 : POPT_COMMON_SAMBA
1223 3256 : POPT_COMMON_CONNECTION
1224 3256 : POPT_COMMON_CREDENTIALS
1225 3256 : POPT_COMMON_VERSION
1226 3256 : POPT_LEGACY_S3
1227 : POPT_TABLEEND
1228 : };
1229 :
1230 : /* Ignore possible SIGPIPE upon ldap_unbind when over TLS */
1231 3256 : BlockSignals(True, SIGPIPE);
1232 :
1233 3256 : zero_sockaddr(&c->opt_dest_ip);
1234 :
1235 3256 : smb_init_locale();
1236 :
1237 3256 : setlocale(LC_ALL, "");
1238 : #if defined(HAVE_BINDTEXTDOMAIN)
1239 3256 : bindtextdomain(MODULE_NAME, get_dyn_LOCALEDIR());
1240 : #endif
1241 : #if defined(HAVE_TEXTDOMAIN)
1242 3256 : textdomain(MODULE_NAME);
1243 : #endif
1244 :
1245 3256 : ok = samba_cmdline_init(frame,
1246 : SAMBA_CMDLINE_CONFIG_CLIENT,
1247 : false /* require_smbconf */);
1248 3256 : if (!ok) {
1249 0 : DBG_ERR("Failed to init cmdline parser!\n");
1250 0 : TALLOC_FREE(frame);
1251 0 : exit(1);
1252 : }
1253 : /* set default debug level to 0 regardless of what smb.conf sets */
1254 3256 : lp_set_cmdline("log level", "0");
1255 3256 : c->private_data = net_func;
1256 :
1257 3256 : pc = samba_popt_get_context(getprogname(),
1258 : argc,
1259 : argv_const,
1260 : long_options,
1261 : POPT_CONTEXT_KEEP_FIRST);
1262 3256 : if (pc == NULL) {
1263 0 : DBG_ERR("Failed to setup popt context!\n");
1264 0 : TALLOC_FREE(frame);
1265 0 : exit(1);
1266 : }
1267 :
1268 6662 : while((opt = poptGetNextOpt(pc)) != -1) {
1269 694 : switch (opt) {
1270 0 : case 'h':
1271 0 : c->display_usage = true;
1272 0 : break;
1273 694 : case 'I':
1274 694 : if (!interpret_string_addr(&c->opt_dest_ip,
1275 694 : poptGetOptArg(pc), 0)) {
1276 0 : d_fprintf(stderr, _("\nInvalid ip address specified\n"));
1277 : } else {
1278 694 : c->opt_have_ip = true;
1279 : }
1280 694 : break;
1281 0 : default:
1282 0 : d_fprintf(stderr, _("\nInvalid option %s: %s\n"),
1283 : poptBadOption(pc, 0), poptStrerror(opt));
1284 0 : net_help(c, argc, argv_const);
1285 0 : exit(1);
1286 : }
1287 : }
1288 :
1289 3252 : c->creds = samba_cmdline_get_creds();
1290 3252 : c->lp_ctx = samba_cmdline_get_lp_ctx();
1291 :
1292 : {
1293 3252 : enum credentials_obtained username_obtained =
1294 : CRED_UNINITIALISED;
1295 2715 : enum smb_encryption_setting encrypt_state =
1296 3252 : cli_credentials_get_smb_encryption(c->creds);
1297 2715 : enum credentials_use_kerberos krb5_state =
1298 3252 : cli_credentials_get_kerberos_state(c->creds);
1299 : uint32_t gensec_features;
1300 :
1301 3252 : c->opt_user_name = cli_credentials_get_username_and_obtained(
1302 : c->creds,
1303 : &username_obtained);
1304 3252 : c->opt_user_specified = (username_obtained == CRED_SPECIFIED);
1305 :
1306 3252 : c->opt_workgroup = cli_credentials_get_domain(c->creds);
1307 :
1308 3252 : c->smb_encrypt = (encrypt_state == SMB_ENCRYPTION_REQUIRED);
1309 :
1310 3252 : c->opt_kerberos = (krb5_state > CRED_USE_KERBEROS_DESIRED);
1311 :
1312 3252 : gensec_features = cli_credentials_get_gensec_features(c->creds);
1313 3252 : c->opt_ccache = (gensec_features & GENSEC_FEATURE_NTLM_CCACHE);
1314 : }
1315 :
1316 3252 : c->msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE());
1317 :
1318 : #if defined(HAVE_BIND_TEXTDOMAIN_CODESET)
1319 : /* Bind our gettext results to 'unix charset'
1320 :
1321 : This ensures that the translations and any embedded strings are in the
1322 : same charset. It won't be the one from the user's locale (we no
1323 : longer auto-detect that), but it will be self-consistent.
1324 : */
1325 3252 : bind_textdomain_codeset(MODULE_NAME, lp_unix_charset());
1326 : #endif
1327 :
1328 3252 : argv_new = (const char **)poptGetArgs(pc);
1329 :
1330 3252 : argc_new = argc;
1331 19342 : for (i=0; i<argc; i++) {
1332 18331 : if (argv_new[i] == NULL) {
1333 2236 : argc_new = i;
1334 2236 : break;
1335 : }
1336 : }
1337 :
1338 3252 : if (c->do_talloc_report) {
1339 0 : talloc_enable_leak_report();
1340 : }
1341 :
1342 3252 : if (c->opt_requester_name) {
1343 0 : lp_set_cmdline("netbios name", c->opt_requester_name);
1344 : }
1345 :
1346 3252 : if (!c->opt_target_workgroup) {
1347 3252 : c->opt_target_workgroup = talloc_strdup(c, lp_workgroup());
1348 : }
1349 :
1350 3252 : load_interfaces();
1351 :
1352 : /* this makes sure that when we do things like call scripts,
1353 : that it won't assert because we are not root */
1354 3252 : sec_init();
1355 :
1356 3252 : samba_cmdline_burn(argc, argv);
1357 :
1358 3252 : rc = net_run_function(c, argc_new-1, argv_new+1, "net", net_func);
1359 :
1360 3252 : DEBUG(2,("return code = %d\n", rc));
1361 :
1362 3252 : libnetapi_free(c->netapi_ctx);
1363 :
1364 3252 : poptFreeContext(pc);
1365 :
1366 3252 : cmdline_messaging_context_free();
1367 3252 : TALLOC_FREE(frame);
1368 3247 : return rc;
1369 : }
|