2 Samba Unix/Linux SMB client library
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6 Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "../utils/net.h"
28 int net_ads_usage(int argc, const char **argv)
31 "\nnet ads join <org_unit>"\
32 "\n\tjoins the local machine to a ADS realm\n"\
34 "\n\tremoves the local machine from a ADS realm\n"\
36 "\n\ttests that an exiting join is OK\n"\
38 "\n\tlist, add, or delete users in the realm\n"\
40 "\n\tlist, add, or delete groups in the realm\n"\
42 "\n\tshows some info on the server\n"\
44 "\n\tdump the machine account details to stdout\n"
46 "\n\tperform a CLDAP search on the server\n"
47 "\nnet ads password <username@realm> -Uadmin_username@realm%%admin_pass"\
48 "\n\tchange a user's password using an admin account"\
49 "\n\t(note: use realm in UPPERCASE)\n"\
50 "\nnet ads chostpass"\
51 "\n\tchange the trust account password of this machine in the AD tree\n"\
52 "\nnet ads printer [info | publish | remove] <printername> <servername>"\
53 "\n\t lookup, add, or remove directory entry for a printer\n"\
55 "\n\tperform a raw LDAP search and dump the results\n"
62 this implements the CLDAP based netlogon lookup requests
63 for finding the domain controller of a ADS domain
65 static int net_ads_lookup(int argc, const char **argv)
69 ads = ads_init(NULL, NULL, opt_host);
71 ads->auth.flags |= ADS_AUTH_NO_BIND;
76 if (!ads || !ads->config.realm) {
77 d_printf("Didn't find the cldap server!\n");
81 return ads_cldap_netlogon(ads);
86 static int net_ads_info(int argc, const char **argv)
90 ads = ads_init(NULL, NULL, opt_host);
93 ads->auth.flags |= ADS_AUTH_NO_BIND;
98 if (!ads || !ads->config.realm) {
99 d_printf("Didn't find the ldap server!\n");
103 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
104 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
105 d_printf("Realm: %s\n", ads->config.realm);
106 d_printf("Bind Path: %s\n", ads->config.bind_path);
107 d_printf("LDAP port: %d\n", ads->ldap_port);
108 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
113 static void use_in_memory_ccache(void) {
114 /* Use in-memory credentials cache so we do not interfere with
115 * existing credentials */
116 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
119 static ADS_STRUCT *ads_startup(void)
123 BOOL need_password = False;
124 BOOL second_time = False;
126 ads = ads_init(NULL, NULL, opt_host);
128 if (!opt_user_name) {
129 opt_user_name = "administrator";
132 if (opt_user_specified) {
133 need_password = True;
134 use_in_memory_ccache();
138 if (!opt_password && need_password) {
140 asprintf(&prompt,"%s password: ", opt_user_name);
141 opt_password = getpass(prompt);
146 ads->auth.password = strdup(opt_password);
148 ads->auth.user_name = strdup(opt_user_name);
150 status = ads_connect(ads);
151 if (!ADS_ERR_OK(status)) {
152 if (!need_password && !second_time) {
153 need_password = True;
157 DEBUG(1,("ads_connect: %s\n", ads_errstr(status)));
166 Check to see if connection can be made via ads.
167 ads_startup() stores the password in opt_password if it needs to so
168 that rpc or rap can use it without re-prompting.
170 int net_ads_check(void)
182 determine the netbios workgroup name for a domain
184 static int net_ads_workgroup(int argc, const char **argv)
190 if (!(ads = ads_startup())) return -1;
192 if (!(ctx = talloc_init("net_ads_workgroup"))) {
196 if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
197 d_printf("Failed to find workgroup for realm '%s'\n",
203 d_printf("Workgroup: %s\n", workgroup);
212 static BOOL usergrp_display(char *field, void **values, void *data_area)
214 char **disp_fields = (char **) data_area;
216 if (!field) { /* must be end of record */
217 if (!strchr_m(disp_fields[0], '$')) {
219 d_printf("%-21.21s %-50.50s\n",
220 disp_fields[0], disp_fields[1]);
222 d_printf("%s\n", disp_fields[0]);
224 SAFE_FREE(disp_fields[0]);
225 SAFE_FREE(disp_fields[1]);
228 if (!values) /* must be new field, indicate string field */
230 if (StrCaseCmp(field, "sAMAccountName") == 0) {
231 disp_fields[0] = strdup((char *) values[0]);
233 if (StrCaseCmp(field, "description") == 0)
234 disp_fields[1] = strdup((char *) values[0]);
238 static int net_ads_user_usage(int argc, const char **argv)
240 return net_help_user(argc, argv);
243 static int ads_user_add(int argc, const char **argv)
251 if (argc < 1) return net_ads_user_usage(argc, argv);
253 if (!(ads = ads_startup())) return -1;
255 status = ads_find_user_acct(ads, &res, argv[0]);
257 if (!ADS_ERR_OK(status)) {
258 d_printf("ads_user_add: %s\n", ads_errstr(status));
262 if (ads_count_replies(ads, res)) {
263 d_printf("ads_user_add: User %s already exists\n", argv[0]);
267 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
269 if (!ADS_ERR_OK(status)) {
270 d_printf("Could not add user %s: %s\n", argv[0],
275 /* if no password is to be set, we're done */
277 d_printf("User %s added\n", argv[0]);
282 /* try setting the password */
283 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
284 status = krb5_set_password(ads->auth.kdc_server, upn, argv[1], ads->auth.time_offset);
286 if (ADS_ERR_OK(status)) {
287 d_printf("User %s added\n", argv[0]);
292 /* password didn't set, delete account */
293 d_printf("Could not add user %s. Error setting password %s\n",
294 argv[0], ads_errstr(status));
295 ads_msgfree(ads, res);
296 status=ads_find_user_acct(ads, &res, argv[0]);
297 if (ADS_ERR_OK(status)) {
298 userdn = ads_get_dn(ads, res);
299 ads_del_dn(ads, userdn);
300 ads_memfree(ads, userdn);
305 ads_msgfree(ads, res);
310 static int ads_user_info(int argc, const char **argv)
315 const char *attrs[] = {"memberOf", NULL};
316 char *searchstring=NULL;
318 char *escaped_user = escape_ldap_string_alloc(argv[0]);
320 if (argc < 1) return net_ads_user_usage(argc, argv);
322 if (!(ads = ads_startup())) return -1;
325 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
329 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
330 rc = ads_search(ads, &res, searchstring, attrs);
331 safe_free(searchstring);
333 if (!ADS_ERR_OK(rc)) {
334 d_printf("ads_search: %s\n", ads_errstr(rc));
338 grouplist = ldap_get_values(ads->ld, res, "memberOf");
343 for (i=0;grouplist[i];i++) {
344 groupname = ldap_explode_dn(grouplist[i], 1);
345 d_printf("%s\n", groupname[0]);
346 ldap_value_free(groupname);
348 ldap_value_free(grouplist);
351 ads_msgfree(ads, res);
357 static int ads_user_delete(int argc, const char **argv)
364 if (argc < 1) return net_ads_user_usage(argc, argv);
366 if (!(ads = ads_startup())) return -1;
368 rc = ads_find_user_acct(ads, &res, argv[0]);
369 if (!ADS_ERR_OK(rc)) {
370 DEBUG(0, ("User %s does not exist\n", argv[0]));
373 userdn = ads_get_dn(ads, res);
374 ads_msgfree(ads, res);
375 rc = ads_del_dn(ads, userdn);
376 ads_memfree(ads, userdn);
377 if (!ADS_ERR_OK(rc)) {
378 d_printf("User %s deleted\n", argv[0]);
381 d_printf("Error deleting user %s: %s\n", argv[0],
386 int net_ads_user(int argc, const char **argv)
388 struct functable func[] = {
389 {"ADD", ads_user_add},
390 {"INFO", ads_user_info},
391 {"DELETE", ads_user_delete},
396 const char *shortattrs[] = {"sAMAccountName", NULL};
397 const char *longattrs[] = {"sAMAccountName", "description", NULL};
398 char *disp_fields[2] = {NULL, NULL};
401 if (!(ads = ads_startup())) return -1;
403 if (opt_long_list_entries)
404 d_printf("\nUser name Comment"\
405 "\n-----------------------------\n");
407 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
409 "(objectclass=user)",
410 opt_long_list_entries ? longattrs :
411 shortattrs, usergrp_display,
417 return net_run_function(argc, argv, func, net_ads_user_usage);
420 static int net_ads_group_usage(int argc, const char **argv)
422 return net_help_group(argc, argv);
425 static int ads_group_add(int argc, const char **argv)
432 if (argc < 1) return net_ads_group_usage(argc, argv);
434 if (!(ads = ads_startup())) return -1;
436 status = ads_find_user_acct(ads, &res, argv[0]);
438 if (!ADS_ERR_OK(status)) {
439 d_printf("ads_group_add: %s\n", ads_errstr(status));
443 if (ads_count_replies(ads, res)) {
444 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
445 ads_msgfree(ads, res);
449 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
451 if (ADS_ERR_OK(status)) {
452 d_printf("Group %s added\n", argv[0]);
455 d_printf("Could not add group %s: %s\n", argv[0],
461 ads_msgfree(ads, res);
466 static int ads_group_delete(int argc, const char **argv)
473 if (argc < 1) return net_ads_group_usage(argc, argv);
475 if (!(ads = ads_startup())) return -1;
477 rc = ads_find_user_acct(ads, &res, argv[0]);
478 if (!ADS_ERR_OK(rc)) {
479 DEBUG(0, ("Group %s does not exist\n", argv[0]));
482 groupdn = ads_get_dn(ads, res);
483 ads_msgfree(ads, res);
484 rc = ads_del_dn(ads, groupdn);
485 ads_memfree(ads, groupdn);
486 if (!ADS_ERR_OK(rc)) {
487 d_printf("Group %s deleted\n", argv[0]);
490 d_printf("Error deleting group %s: %s\n", argv[0],
495 int net_ads_group(int argc, const char **argv)
497 struct functable func[] = {
498 {"ADD", ads_group_add},
499 {"DELETE", ads_group_delete},
504 const char *shortattrs[] = {"sAMAccountName", NULL};
505 const char *longattrs[] = {"sAMAccountName", "description", NULL};
506 char *disp_fields[2] = {NULL, NULL};
509 if (!(ads = ads_startup())) return -1;
511 if (opt_long_list_entries)
512 d_printf("\nGroup name Comment"\
513 "\n-----------------------------\n");
514 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
516 "(objectclass=group)",
517 opt_long_list_entries ? longattrs :
518 shortattrs, usergrp_display,
524 return net_run_function(argc, argv, func, net_ads_group_usage);
527 static int net_ads_status(int argc, const char **argv)
533 if (!(ads = ads_startup())) return -1;
535 rc = ads_find_machine_acct(ads, &res, global_myname());
536 if (!ADS_ERR_OK(rc)) {
537 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
541 if (ads_count_replies(ads, res) == 0) {
542 d_printf("No machine account for '%s' found\n", global_myname());
551 static int net_ads_leave(int argc, const char **argv)
553 ADS_STRUCT *ads = NULL;
556 if (!secrets_init()) {
557 DEBUG(1,("Failed to initialise secrets database\n"));
563 asprintf(&user_name, "%s$", global_myname());
564 opt_password = secrets_fetch_machine_password();
565 opt_user_name = user_name;
568 if (!(ads = ads_startup())) {
572 rc = ads_leave_realm(ads, global_myname());
573 if (!ADS_ERR_OK(rc)) {
574 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
575 global_myname(), ads->config.realm);
579 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
584 static int net_ads_join_ok(void)
587 ADS_STRUCT *ads = NULL;
589 if (!secrets_init()) {
590 DEBUG(1,("Failed to initialise secrets database\n"));
594 asprintf(&user_name, "%s$", global_myname());
595 opt_user_name = user_name;
596 opt_password = secrets_fetch_machine_password();
598 if (!(ads = ads_startup())) {
607 check that an existing join is OK
609 int net_ads_testjoin(int argc, const char **argv)
611 use_in_memory_ccache();
613 /* Display success or failure */
614 if (net_ads_join_ok() != 0) {
615 fprintf(stderr,"Join to domain is not valid\n");
619 printf("Join is OK\n");
624 join a domain using ADS
626 int net_ads_join(int argc, const char **argv)
632 const char *org_unit = "Computers";
638 if (argc > 0) org_unit = argv[0];
640 if (!secrets_init()) {
641 DEBUG(1,("Failed to initialise secrets database\n"));
645 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
646 password = strdup(tmp_password);
648 if (!(ads = ads_startup())) return -1;
650 ou_str = ads_ou_string(org_unit);
651 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
654 rc = ads_search_dn(ads, &res, dn, NULL);
655 ads_msgfree(ads, res);
657 if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
658 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
664 if (!ADS_ERR_OK(rc)) {
665 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
669 rc = ads_join_realm(ads, global_myname(), org_unit);
670 if (!ADS_ERR_OK(rc)) {
671 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
675 rc = ads_domain_sid(ads, &dom_sid);
676 if (!ADS_ERR_OK(rc)) {
677 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
681 rc = ads_set_machine_password(ads, global_myname(), password);
682 if (!ADS_ERR_OK(rc)) {
683 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
687 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
688 DEBUG(1,("Failed to save domain sid\n"));
692 if (!secrets_store_machine_password(password)) {
693 DEBUG(1,("Failed to save machine password\n"));
697 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
704 int net_ads_printer_usage(int argc, const char **argv)
707 "\nnet ads printer info <printer> <server>"
708 "\n\tlookup info in directory for printer on server"
709 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
710 "\nnet ads printer publish <printername>"
711 "\n\tpublish printer in directory"
712 "\n\t(note: printer name is required)\n"
713 "\nnet ads printer remove <printername>"
714 "\n\tremove printer from directory"
715 "\n\t(note: printer name is required)\n");
719 static int net_ads_printer_info(int argc, const char **argv)
723 const char *servername, *printername;
726 if (!(ads = ads_startup())) return -1;
729 printername = argv[0];
734 servername = argv[1];
736 servername = global_myname();
738 rc = ads_find_printer_on_server(ads, &res, printername, servername);
740 if (!ADS_ERR_OK(rc)) {
741 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
742 ads_msgfree(ads, res);
746 if (ads_count_replies(ads, res) == 0) {
747 d_printf("Printer '%s' not found\n", printername);
748 ads_msgfree(ads, res);
753 ads_msgfree(ads, res);
758 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
763 static int net_ads_printer_publish(int argc, const char **argv)
767 const char *servername;
768 struct cli_state *cli;
769 struct in_addr server_ip;
771 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
772 ADS_MODLIST mods = ads_init_mods(mem_ctx);
773 char *prt_dn, *srv_dn, **srv_cn;
776 if (!(ads = ads_startup())) return -1;
779 return net_ads_printer_usage(argc, argv);
782 servername = argv[1];
784 servername = global_myname();
786 ads_find_machine_acct(ads, &res, servername);
787 srv_dn = ldap_get_dn(ads->ld, res);
788 srv_cn = ldap_explode_dn(srv_dn, 1);
789 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], argv[0], srv_dn);
791 resolve_name(servername, &server_ip, 0x20);
793 nt_status = cli_full_connection(&cli, global_myname(), servername,
796 opt_user_name, opt_workgroup,
797 opt_password ? opt_password : "",
798 CLI_FULL_CONNECTION_USE_KERBEROS,
801 cli_nt_session_open(cli, PI_SPOOLSS);
802 get_remote_printer_publishing_data(cli, mem_ctx, &mods, argv[0]);
804 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
805 if (!ADS_ERR_OK(rc)) {
806 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
810 d_printf("published printer\n");
815 static int net_ads_printer_remove(int argc, const char **argv)
819 const char *servername;
823 if (!(ads = ads_startup())) return -1;
826 return net_ads_printer_usage(argc, argv);
829 servername = argv[1];
831 servername = global_myname();
833 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
835 if (!ADS_ERR_OK(rc)) {
836 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
837 ads_msgfree(ads, res);
841 if (ads_count_replies(ads, res) == 0) {
842 d_printf("Printer '%s' not found\n", argv[1]);
843 ads_msgfree(ads, res);
847 prt_dn = ads_get_dn(ads, res);
848 ads_msgfree(ads, res);
849 rc = ads_del_dn(ads, prt_dn);
850 ads_memfree(ads, prt_dn);
852 if (!ADS_ERR_OK(rc)) {
853 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
860 static int net_ads_printer(int argc, const char **argv)
862 struct functable func[] = {
863 {"INFO", net_ads_printer_info},
864 {"PUBLISH", net_ads_printer_publish},
865 {"REMOVE", net_ads_printer_remove},
869 return net_run_function(argc, argv, func, net_ads_printer_usage);
873 static int net_ads_password(int argc, const char **argv)
876 const char *auth_principal = opt_user_name;
877 const char *auth_password = opt_password;
879 char *new_password = NULL;
885 if ((argc != 1) || (opt_user_name == NULL) ||
886 (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
887 (strchr(argv[0], '@') == NULL)) {
888 return net_ads_usage(argc, argv);
891 use_in_memory_ccache();
892 c = strchr(auth_principal, '@');
895 /* use the realm so we can eventually change passwords for users
896 in realms other than default */
897 if (!(ads = ads_init(realm, NULL, NULL))) return -1;
899 asprintf(&prompt, "Enter new password for %s:", argv[0]);
901 new_password = getpass(prompt);
903 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
904 auth_password, argv[0], new_password, ads->auth.time_offset);
905 if (!ADS_ERR_OK(ret)) {
906 d_printf("Password change failed :-( ...\n");
912 d_printf("Password change for %s completed.\n", argv[0]);
920 static int net_ads_change_localhost_pass(int argc, const char **argv)
923 char *host_principal;
928 if (!secrets_init()) {
929 DEBUG(1,("Failed to initialise secrets database\n"));
933 asprintf(&user_name, "%s$", global_myname());
934 opt_user_name = user_name;
936 opt_password = secrets_fetch_machine_password();
938 use_in_memory_ccache();
940 if (!(ads = ads_startup())) {
944 hostname = strdup(global_myname());
946 asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
948 d_printf("Changing password for principal: HOST/%s\n", host_principal);
950 ret = ads_change_trust_account_password(ads, host_principal);
952 if (!ADS_ERR_OK(ret)) {
953 d_printf("Password change failed :-( ...\n");
955 SAFE_FREE(host_principal);
959 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
961 SAFE_FREE(host_principal);
967 help for net ads search
969 static int net_ads_search_usage(int argc, const char **argv)
972 "\nnet ads search <expression> <attributes...>\n"\
973 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
974 "The expression is a standard LDAP search expression, and the\n"\
975 "attributes are a list of LDAP fields to show in the results\n\n"\
976 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
978 net_common_flags_usage(argc, argv);
984 general ADS search function. Useful in diagnosing problems in ADS
986 static int net_ads_search(int argc, const char **argv)
995 return net_ads_search_usage(argc, argv);
998 if (!(ads = ads_startup())) {
1005 rc = ads_do_search_all(ads, ads->config.bind_path,
1008 if (!ADS_ERR_OK(rc)) {
1009 d_printf("search failed: %s\n", ads_errstr(rc));
1013 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1015 /* dump the results */
1018 ads_msgfree(ads, res);
1025 int net_ads_help(int argc, const char **argv)
1027 struct functable func[] = {
1028 {"USER", net_ads_user_usage},
1029 {"GROUP", net_ads_group_usage},
1030 {"PRINTER", net_ads_printer_usage},
1031 {"SEARCH", net_ads_search_usage},
1033 {"INFO", net_ads_info},
1034 {"JOIN", net_ads_join},
1035 {"LEAVE", net_ads_leave},
1036 {"STATUS", net_ads_status},
1037 {"PASSWORD", net_ads_password},
1038 {"CHOSTPASS", net_ads_change_localhost_pass},
1043 return net_run_function(argc, argv, func, net_ads_usage);
1046 int net_ads(int argc, const char **argv)
1048 struct functable func[] = {
1049 {"INFO", net_ads_info},
1050 {"JOIN", net_ads_join},
1051 {"TESTJOIN", net_ads_testjoin},
1052 {"LEAVE", net_ads_leave},
1053 {"STATUS", net_ads_status},
1054 {"USER", net_ads_user},
1055 {"GROUP", net_ads_group},
1056 {"PASSWORD", net_ads_password},
1057 {"CHOSTPASS", net_ads_change_localhost_pass},
1058 {"PRINTER", net_ads_printer},
1059 {"SEARCH", net_ads_search},
1060 {"WORKGROUP", net_ads_workgroup},
1061 {"LOOKUP", net_ads_lookup},
1062 {"HELP", net_ads_help},
1066 return net_run_function(argc, argv, func, net_ads_usage);
1071 static int net_ads_noads(void)
1073 d_printf("ADS support not compiled in\n");
1077 int net_ads_usage(int argc, const char **argv)
1079 return net_ads_noads();
1082 int net_ads_help(int argc, const char **argv)
1084 return net_ads_noads();
1087 int net_ads_join(int argc, const char **argv)
1089 return net_ads_noads();
1092 int net_ads_user(int argc, const char **argv)
1094 return net_ads_noads();
1097 int net_ads_group(int argc, const char **argv)
1099 return net_ads_noads();
1102 /* this one shouldn't display a message */
1103 int net_ads_check(void)
1108 int net_ads(int argc, const char **argv)
1110 return net_ads_usage(argc, argv);