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)
10 Originally written by Steve and Jim. Largely rewritten by tridge in
13 Reworked again by abartlet in December 2001
15 Another overhaul, moving functionality into plug-ins loaded on demand by Kai
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.
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.
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/>. */
31 /*****************************************************/
33 /* Distributed SMB/CIFS Server Management Utility */
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 */
41 /*****************************************************/
44 #include "popt_common.h"
45 #include "utils/net.h"
47 #include "lib/netapi/netapi.h"
48 #include "../libcli/security/security.h"
52 #ifdef WITH_FAKE_KASERVER
53 #include "utils/net_afs.h"
56 /***********************************************************************/
57 /* end of internationalization section */
58 /***********************************************************************/
60 enum netr_SchannelType
get_sec_channel_type(const char *param
)
62 if (!(param
&& *param
)) {
63 return get_default_sec_channel();
65 if (strequal(param
, "PDC")) {
67 } else if (strequal(param
, "BDC")) {
69 } else if (strequal(param
, "MEMBER")) {
70 return SEC_CHAN_WKSTA
;
72 } else if (strequal(param
, "DOMAIN")) {
73 return SEC_CHAN_DOMAIN
;
76 return get_default_sec_channel();
81 static int net_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
83 if (net_ads_check_our_domain(c
) == 0)
84 return net_ads_changetrustpw(c
, argc
, argv
);
86 return net_rpc_changetrustpw(c
, argc
, argv
);
89 static void set_line_buffering(FILE *f
)
91 setvbuf(f
, NULL
, _IOLBF
, 0);
94 static int net_changesecretpw(struct net_context
*c
, int argc
,
98 enum netr_SchannelType sec_channel_type
= SEC_CHAN_WKSTA
;
102 set_line_buffering(stdin
);
103 set_line_buffering(stdout
);
104 set_line_buffering(stderr
);
107 trust_pw
= get_pass(_("Enter machine password: "), c
->opt_stdin
);
109 if (!secrets_store_machine_password(trust_pw
, lp_workgroup(), sec_channel_type
)) {
111 _("Unable to write the machine account password in the secrets database"));
115 d_printf(_("Modified trust account password in secrets database\n"));
119 d_printf(_("Machine account password change requires the -f flag.\n"
120 "Do NOT use this function unless you know what it does!\n"
121 "This function will change the ADS Domain member "
122 "machine account password in the secrets.tdb file!\n"));
129 * @brief Set the authorised user for winbindd access in secrets.tdb
131 static int net_setauthuser(struct net_context
*c
, int argc
, const char **argv
)
133 const char *password
= NULL
;
135 if (!secrets_init()) {
136 d_fprintf(stderr
, _("Failed to open secrets.tdb.\n"));
140 /* Delete the settings. */
142 if (strncmp(argv
[0], "delete", 6) != 0) {
143 d_fprintf(stderr
,_("Usage:\n"));
145 _(" net setauthuser -U user[%%password] \n"
146 " Set the auth user account to user"
147 "password. Prompt for password if not "
150 _(" net setauthuser delete\n"
151 " Delete the auth user setting.\n"));
154 secrets_delete(SECRETS_AUTH_USER
);
155 secrets_delete(SECRETS_AUTH_DOMAIN
);
156 secrets_delete(SECRETS_AUTH_PASSWORD
);
160 if (!c
->opt_user_specified
) {
161 d_fprintf(stderr
, _("Usage:\n"));
163 _(" net setauthuser -U user[%%password]\n"
164 " Set the auth user account to user"
165 "password. Prompt for password if not "
168 _(" net setauthuser delete\n"
169 " Delete the auth user setting.\n"));
173 password
= net_prompt_pass(c
, _("the auth user"));
174 if (password
== NULL
) {
175 d_fprintf(stderr
,_("Failed to get the auth users password.\n"));
179 if (!secrets_store(SECRETS_AUTH_USER
, c
->opt_user_name
,
180 strlen(c
->opt_user_name
) + 1)) {
181 d_fprintf(stderr
, _("error storing auth user name\n"));
185 if (!secrets_store(SECRETS_AUTH_DOMAIN
, c
->opt_workgroup
,
186 strlen(c
->opt_workgroup
) + 1)) {
187 d_fprintf(stderr
, _("error storing auth user domain\n"));
191 if (!secrets_store(SECRETS_AUTH_PASSWORD
, password
,
192 strlen(password
) + 1)) {
193 d_fprintf(stderr
, _("error storing auth user password\n"));
201 * @brief Get the auth user settings
203 static int net_getauthuser(struct net_context
*c
, int argc
, const char **argv
)
205 char *user
, *domain
, *password
;
207 /* Lift data from secrets file */
209 secrets_fetch_ipc_userpass(&user
, &domain
, &password
);
211 if ((!user
|| !*user
) && (!domain
|| !*domain
) &&
212 (!password
|| !*password
)){
217 d_printf(_("No authorised user configured\n"));
221 /* Pretty print authorised user info */
223 d_printf("%s%s%s%s%s\n", domain
? domain
: "",
224 domain
? lp_winbind_separator(): "", user
,
225 password
? "%" : "", password
? password
: "");
234 Retrieve our local SID or the SID for the specified name
236 static int net_getlocalsid(struct net_context
*c
, int argc
, const char **argv
)
246 name
= lp_netbios_name();
249 if(!initialize_password_db(false, NULL
)) {
250 DEBUG(0, ("WARNING: Could not open passdb - local sid may not reflect passdb\n"
251 "backend knowledge (such as the sid stored in LDAP)\n"));
254 /* first check to see if we can even access secrets, so we don't
255 panic when we can't. */
257 if (!secrets_init()) {
259 _("Unable to open secrets.tdb. Can't fetch domain "
260 "SID for name: %s\n"), name
);
264 /* Generate one, if it doesn't exist */
265 get_global_sam_sid();
267 if (!secrets_fetch_domain_sid(name
, &sid
)) {
268 DEBUG(0, ("Can't fetch domain SID for name: %s\n", name
));
271 sid_to_fstring(sid_str
, &sid
);
272 d_printf(_("SID for domain %s is: %s\n"), name
, sid_str
);
276 static int net_setlocalsid(struct net_context
*c
, int argc
, const char **argv
)
281 || (strncmp(argv
[0], "S-1-5-21-", strlen("S-1-5-21-")) != 0)
282 || (!string_to_sid(&sid
, argv
[0]))
283 || (sid
.num_auths
!= 4)) {
284 d_printf(_("Usage:"));
285 d_printf(" net setlocalsid S-1-5-21-x-y-z\n");
289 if (!secrets_store_domain_sid(lp_netbios_name(), &sid
)) {
290 DEBUG(0,("Can't store domain SID as a pdc/bdc.\n"));
297 static int net_setdomainsid(struct net_context
*c
, int argc
, const char **argv
)
302 || (strncmp(argv
[0], "S-1-5-21-", strlen("S-1-5-21-")) != 0)
303 || (!string_to_sid(&sid
, argv
[0]))
304 || (sid
.num_auths
!= 4)) {
305 d_printf(_("Usage:"));
306 d_printf(" net setdomainsid S-1-5-21-x-y-z\n");
310 if (!secrets_store_domain_sid(lp_workgroup(), &sid
)) {
311 DEBUG(0,("Can't store domain SID.\n"));
318 static int net_getdomainsid(struct net_context
*c
, int argc
, const char **argv
)
320 struct dom_sid domain_sid
;
324 d_printf(_("Usage:"));
325 d_printf(" net getdomainsid\n");
329 if(!initialize_password_db(false, NULL
)) {
330 DEBUG(0, ("WARNING: Could not open passdb - domain SID may "
331 "not reflect passdb\n"
332 "backend knowledge (such as the SID stored in "
336 /* first check to see if we can even access secrets, so we don't
337 panic when we can't. */
339 if (!secrets_init()) {
340 d_fprintf(stderr
, _("Unable to open secrets.tdb. Can't fetch "
341 "domain SID for name: %s\n"),
342 get_global_sam_name());
346 /* Generate one, if it doesn't exist */
347 get_global_sam_sid();
349 if (!secrets_fetch_domain_sid(lp_netbios_name(), &domain_sid
)) {
350 d_fprintf(stderr
, _("Could not fetch local SID\n"));
353 sid_to_fstring(sid_str
, &domain_sid
);
354 d_printf(_("SID for local machine %s is: %s\n"),
355 lp_netbios_name(), sid_str
);
357 if (!secrets_fetch_domain_sid(c
->opt_workgroup
, &domain_sid
)) {
358 d_fprintf(stderr
, _("Could not fetch domain SID\n"));
362 sid_to_fstring(sid_str
, &domain_sid
);
363 d_printf(_("SID for domain %s is: %s\n"), c
->opt_workgroup
, sid_str
);
368 static bool search_maxrid(struct pdb_search
*search
, const char *type
,
371 struct samr_displayentry
*entries
;
372 uint32 i
, num_entries
;
374 if (search
== NULL
) {
375 d_fprintf(stderr
, _("get_maxrid: Could not search %s\n"), type
);
379 num_entries
= pdb_search_entries(search
, 0, 0xffffffff, &entries
);
380 for (i
=0; i
<num_entries
; i
++)
381 *max_rid
= MAX(*max_rid
, entries
[i
].rid
);
386 static uint32
get_maxrid(void)
390 if (!search_maxrid(pdb_search_users(talloc_tos(), 0), "users", &max_rid
))
393 if (!search_maxrid(pdb_search_groups(talloc_tos()), "groups", &max_rid
))
396 if (!search_maxrid(pdb_search_aliases(talloc_tos(),
397 get_global_sam_sid()),
398 "aliases", &max_rid
))
404 static int net_maxrid(struct net_context
*c
, int argc
, const char **argv
)
409 d_fprintf(stderr
, "%s net maxrid\n", _("Usage:"));
413 if ((rid
= get_maxrid()) == 0) {
414 d_fprintf(stderr
, _("can't get current maximum rid\n"));
418 d_printf(_("Currently used maximum rid: %d\n"), rid
);
423 /* main function table */
424 static struct functable net_func
[] = {
429 N_("Run functions using RPC transport"),
430 N_(" Use 'net help rpc' to get more extensive information "
431 "about 'net rpc' commands.")
437 N_("Run functions using RAP transport"),
438 N_(" Use 'net help rap' to get more extensive information "
439 "about 'net rap' commands.")
445 N_("Run functions using ADS transport"),
446 N_(" Use 'net help ads' to get more extensive information "
447 "about 'net ads' commands.")
450 /* eventually these should auto-choose the transport ... */
454 NET_TRANSPORT_RPC
| NET_TRANSPORT_RAP
,
455 N_("Functions on remote opened files"),
456 N_(" Use 'net help file' to get more information about 'net "
462 NET_TRANSPORT_RPC
| NET_TRANSPORT_RAP
,
463 N_("Functions on shares"),
464 N_(" Use 'net help share' to get more information about 'net "
471 N_("Manage sessions"),
472 N_(" Use 'net help session' to get more information about "
473 "'net session' commands.")
479 N_("List servers in workgroup"),
480 N_(" Use 'net help server' to get more information about 'net "
487 N_("List domains/workgroups on network"),
488 N_(" Use 'net help domain' to get more information about 'net "
495 N_("Modify printer queue"),
496 N_(" Use 'net help printq' to get more information about 'net "
502 NET_TRANSPORT_ADS
| NET_TRANSPORT_RPC
| NET_TRANSPORT_RAP
,
504 N_(" Use 'net help user' to get more information about 'net "
510 NET_TRANSPORT_ADS
| NET_TRANSPORT_RPC
| NET_TRANSPORT_RAP
,
512 N_(" Use 'net help group' to get more information about 'net "
519 N_("Manage group mappings"),
520 N_(" Use 'net help groupmap' to get more information about "
521 "'net groupmap' commands.")
527 N_("Functions on the SAM database"),
528 N_(" Use 'net help sam' to get more information about 'net "
535 N_("Validate username and password"),
536 N_(" Use 'net help validate' to get more information about "
537 "'net validate' commands.")
543 N_("Modify group memberships"),
544 N_(" Use 'net help groupmember' to get more information about "
545 "'net groupmember' commands.")
550 N_("Execute remote command on a remote OS/2 server"),
551 N_(" Use 'net help admin' to get more information about 'net "
557 N_("List/modify running services"),
558 N_(" Use 'net help service' to get more information about "
559 "'net service' commands.")
565 N_("Change user password on target server"),
566 N_(" Use 'net help password' to get more information about "
567 "'net password' commands.")
571 NET_TRANSPORT_ADS
| NET_TRANSPORT_RPC
,
572 N_("Change the trust password"),
573 N_(" Use 'net help changetrustpw' to get more information "
574 "about 'net changetrustpw'.")
579 N_("Change the secret password"),
580 N_(" net [options] changesecretpw\n"
581 " Change the ADS domain member machine account password "
583 " Do NOT use this function unless you know what it does.\n"
584 " Requires the -f flag to work.")
590 N_("Set the winbind auth user"),
591 N_(" net -U user[%%password] [-W domain] setauthuser\n"
592 " Set the auth user, password (and optionally domain\n"
593 " Will prompt for password if not given.\n"
594 " net setauthuser delete\n"
595 " Delete the existing auth user settings.")
601 N_("Get the winbind auth user settings"),
602 N_(" net getauthuser\n"
603 " Get the current winbind auth user settings.")
609 N_(" Use 'net help time' to get more information about 'net "
615 N_("Look up host names/IP addresses"),
616 N_(" Use 'net help lookup' to get more information about 'net "
622 N_("Manipulate the global lock table"),
623 N_(" Use 'net help g_lock' to get more information about "
624 "'net g_lock' commands.")
628 NET_TRANSPORT_ADS
| NET_TRANSPORT_RPC
,
629 N_("Join a domain/AD"),
630 N_(" Use 'net help join' to get more information about 'net "
636 N_("Join/unjoin (remote) machines to/from a domain/AD"),
637 N_(" Use 'net help dom' to get more information about 'net "
643 N_("Operate on the cache tdb file"),
644 N_(" Use 'net help cache' to get more information about 'net "
650 N_("Get the SID for the local domain"),
651 N_(" net getlocalsid")
656 N_("Set the SID for the local domain"),
657 N_(" net setlocalsid S-1-5-21-x-y-z")
662 N_("Set domain SID on member servers"),
663 N_(" net setdomainsid S-1-5-21-x-y-z")
668 N_("Get domain SID on member servers"),
669 N_(" net getdomainsid")
674 N_("Display the maximum RID currently used"),
680 N_("IDmap functions"),
681 N_(" Use 'net help idmap to get more information about 'net "
687 N_("Display server status"),
688 N_(" Use 'net help status' to get more information about 'net "
694 N_("Manage user-modifiable shares"),
695 N_(" Use 'net help usershare to get more information about "
696 "'net usershare' commands.")
701 N_("Display list of all users with SID"),
702 N_(" Use 'net help usersidlist' to get more information about "
703 "'net usersidlist'.")
708 N_("Manage Samba registry based configuration"),
709 N_(" Use 'net help conf' to get more information about 'net "
715 N_("Manage the Samba registry"),
716 N_(" Use 'net help registry' to get more information about "
717 "'net registry' commands.")
722 N_("Process Win32 *.evt eventlog files"),
723 N_(" Use 'net help eventlog' to get more information about "
724 "'net eventlog' commands.")
729 N_("Process tdb printer files"),
730 N_(" Use 'net help printing' to get more information about "
731 "'net printing' commands.")
737 N_("Manage the serverid tdb"),
738 N_(" Use 'net help serverid' to get more information about "
739 "'net serverid' commands.")
742 #ifdef WITH_FAKE_KASERVER
746 N_("Manage AFS tokens"),
747 N_(" Use 'net help afs' to get more information about 'net "
755 N_("Print usage information"),
756 N_(" Use 'net help help' to list usage information for 'net' "
759 {NULL
, NULL
, 0, NULL
, NULL
}
763 /****************************************************************************
765 ****************************************************************************/
766 int main(int argc
, const char **argv
)
772 const char ** argv_new
;
774 TALLOC_CTX
*frame
= talloc_stackframe();
775 struct net_context
*c
= talloc_zero(frame
, struct net_context
);
777 struct poptOption long_options
[] = {
778 {"help", 'h', POPT_ARG_NONE
, 0, 'h'},
779 {"workgroup", 'w', POPT_ARG_STRING
, &c
->opt_target_workgroup
},
780 {"user", 'U', POPT_ARG_STRING
, &c
->opt_user_name
, 'U'},
781 {"ipaddress", 'I', POPT_ARG_STRING
, 0,'I'},
782 {"port", 'p', POPT_ARG_INT
, &c
->opt_port
},
783 {"myname", 'n', POPT_ARG_STRING
, &c
->opt_requester_name
},
784 {"server", 'S', POPT_ARG_STRING
, &c
->opt_host
},
785 {"encrypt", 'e', POPT_ARG_NONE
, NULL
, 'e', N_("Encrypt SMB transport (UNIX extended servers only)") },
786 {"container", 'c', POPT_ARG_STRING
, &c
->opt_container
},
787 {"comment", 'C', POPT_ARG_STRING
, &c
->opt_comment
},
788 {"maxusers", 'M', POPT_ARG_INT
, &c
->opt_maxusers
},
789 {"flags", 'F', POPT_ARG_INT
, &c
->opt_flags
},
790 {"long", 'l', POPT_ARG_NONE
, &c
->opt_long_list_entries
},
791 {"reboot", 'r', POPT_ARG_NONE
, &c
->opt_reboot
},
792 {"force", 'f', POPT_ARG_NONE
, &c
->opt_force
},
793 {"stdin", 'i', POPT_ARG_NONE
, &c
->opt_stdin
},
794 {"timeout", 't', POPT_ARG_INT
, &c
->opt_timeout
},
795 {"request-timeout",0,POPT_ARG_INT
, &c
->opt_request_timeout
},
796 {"machine-pass",'P', POPT_ARG_NONE
, &c
->opt_machine_pass
},
797 {"kerberos", 'k', POPT_ARG_NONE
, &c
->opt_kerberos
},
798 {"myworkgroup", 'W', POPT_ARG_STRING
, &c
->opt_workgroup
},
799 {"use-ccache", 0, POPT_ARG_NONE
, &c
->opt_ccache
},
800 {"verbose", 'v', POPT_ARG_NONE
, &c
->opt_verbose
},
801 {"test", 'T', POPT_ARG_NONE
, &c
->opt_testmode
},
802 /* Options for 'net groupmap set' */
803 {"local", 'L', POPT_ARG_NONE
, &c
->opt_localgroup
},
804 {"domain", 'D', POPT_ARG_NONE
, &c
->opt_domaingroup
},
805 {"ntname", 'N', POPT_ARG_STRING
, &c
->opt_newntname
},
806 {"rid", 'R', POPT_ARG_INT
, &c
->opt_rid
},
807 /* Options for 'net rpc share migrate' */
808 {"acls", 0, POPT_ARG_NONE
, &c
->opt_acls
},
809 {"attrs", 0, POPT_ARG_NONE
, &c
->opt_attrs
},
810 {"timestamps", 0, POPT_ARG_NONE
, &c
->opt_timestamps
},
811 {"exclude", 'X', POPT_ARG_STRING
, &c
->opt_exclude
},
812 {"destination", 0, POPT_ARG_STRING
, &c
->opt_destination
},
813 {"tallocreport", 0, POPT_ARG_NONE
, &c
->do_talloc_report
},
814 /* Options for 'net rpc vampire (keytab)' */
815 {"force-full-repl", 0, POPT_ARG_NONE
, &c
->opt_force_full_repl
},
816 {"single-obj-repl", 0, POPT_ARG_NONE
, &c
->opt_single_obj_repl
},
817 {"clean-old-entries", 0, POPT_ARG_NONE
, &c
->opt_clean_old_entries
},
818 /* Options for 'net idmap'*/
819 {"db", 0, POPT_ARG_STRING
, &c
->opt_db
},
820 {"lock", 0, POPT_ARG_NONE
, &c
->opt_lock
},
821 {"auto", 'a', POPT_ARG_NONE
, &c
->opt_auto
},
822 {"repair", 0, POPT_ARG_NONE
, &c
->opt_repair
},
827 zero_sockaddr(&c
->opt_dest_ip
);
829 setup_logging(argv
[0], DEBUG_STDERR
);
833 setlocale(LC_ALL
, "");
834 #if defined(HAVE_BINDTEXTDOMAIN)
835 bindtextdomain(MODULE_NAME
, get_dyn_LOCALEDIR());
837 #if defined(HAVE_TEXTDOMAIN)
838 textdomain(MODULE_NAME
);
841 /* set default debug level to 0 regardless of what smb.conf sets */
842 lp_set_cmdline("log level", "0");
843 c
->private_data
= net_func
;
845 pc
= poptGetContext(NULL
, argc
, (const char **) argv
, long_options
,
846 POPT_CONTEXT_KEEP_FIRST
);
848 while((opt
= poptGetNextOpt(pc
)) != -1) {
851 c
->display_usage
= true;
854 c
->smb_encrypt
= true;
857 if (!interpret_string_addr(&c
->opt_dest_ip
,
858 poptGetOptArg(pc
), 0)) {
859 d_fprintf(stderr
, _("\nInvalid ip address specified\n"));
861 c
->opt_have_ip
= true;
865 c
->opt_user_specified
= true;
866 c
->opt_user_name
= SMB_STRDUP(c
->opt_user_name
);
867 p
= strchr(c
->opt_user_name
,'%');
870 c
->opt_password
= p
+1;
874 d_fprintf(stderr
, _("\nInvalid option %s: %s\n"),
875 poptBadOption(pc
, 0), poptStrerror(opt
));
876 net_help(c
, argc
, argv
);
881 lp_load_global(get_dyn_CONFIGFILE());
883 #if defined(HAVE_BIND_TEXTDOMAIN_CODESET)
884 /* Bind our gettext results to 'unix charset'
886 This ensures that the translations and any embedded strings are in the
887 same charset. It won't be the one from the user's locale (we no
888 longer auto-detect that), but it will be self-consistent.
890 bind_textdomain_codeset(MODULE_NAME
, lp_unix_charset());
893 argv_new
= (const char **)poptGetArgs(pc
);
896 for (i
=0; i
<argc
; i
++) {
897 if (argv_new
[i
] == NULL
) {
903 if (c
->do_talloc_report
) {
904 talloc_enable_leak_report();
907 if (c
->opt_requester_name
) {
908 lp_set_cmdline("netbios name", c
->opt_requester_name
);
911 if (!c
->opt_user_name
&& getenv("LOGNAME")) {
912 c
->opt_user_name
= getenv("LOGNAME");
915 if (!c
->opt_workgroup
) {
916 c
->opt_workgroup
= smb_xstrdup(lp_workgroup());
919 if (!c
->opt_target_workgroup
) {
920 c
->opt_target_workgroup
= smb_xstrdup(lp_workgroup());
928 /* this makes sure that when we do things like call scripts,
929 that it won't assert because we are not root */
932 if (c
->opt_machine_pass
) {
933 /* it is very useful to be able to make ads queries as the
934 machine account for testing purposes and for domain leave */
936 net_use_krb_machine_account(c
);
939 if (!c
->opt_password
) {
940 c
->opt_password
= getenv("PASSWD");
943 /* Failing to init the msg_ctx isn't a fatal error. Only
944 root-level things (joining/leaving domains etc.) will be denied. */
946 c
->msg_ctx
= messaging_init(c
, procid_self(),
947 event_context_init(c
));
949 rc
= net_run_function(c
, argc_new
-1, argv_new
+1, "net", net_func
);
951 DEBUG(2,("return code = %d\n", rc
));
953 gencache_stabilize();
955 libnetapi_free(c
->netapi_ctx
);