83aef18cef1293272f79657a36d355186fff98e3
[samba.git] / source3 / utils / net_ads.c
1 /*
2    Samba Unix/Linux SMB client library
3    net ads commands
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)
7    Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "../librpc/gen_ndr/cli_spoolss.h"
27 #include "nsswitch/libwbclient/wbclient.h"
28
29 #ifdef HAVE_ADS
30
31 /* when we do not have sufficient input parameters to contact a remote domain
32  * we always fall back to our own realm - Guenther*/
33
34 static const char *assume_own_realm(struct net_context *c)
35 {
36         if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
37                 return lp_realm();
38         }
39
40         return NULL;
41 }
42
43 /*
44   do a cldap netlogon query
45 */
46 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
47 {
48         char addr[INET6_ADDRSTRLEN];
49         struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
50
51         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
52         if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
53                 d_fprintf(stderr, _("CLDAP query failed!\n"));
54                 return -1;
55         }
56
57         d_printf(_("Information for Domain Controller: %s\n\n"),
58                 addr);
59
60         d_printf(_("Response Type: "));
61         switch (reply.command) {
62         case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
63                 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
64                 break;
65         case LOGON_SAM_LOGON_RESPONSE_EX:
66                 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
67                 break;
68         default:
69                 d_printf("0x%x\n", reply.command);
70                 break;
71         }
72
73         d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
74
75         d_printf(_("Flags:\n"
76                    "\tIs a PDC:                                   %s\n"
77                    "\tIs a GC of the forest:                      %s\n"
78                    "\tIs an LDAP server:                          %s\n"
79                    "\tSupports DS:                                %s\n"
80                    "\tIs running a KDC:                           %s\n"
81                    "\tIs running time services:                   %s\n"
82                    "\tIs the closest DC:                          %s\n"
83                    "\tIs writable:                                %s\n"
84                    "\tHas a hardware clock:                       %s\n"
85                    "\tIs a non-domain NC serviced by LDAP server: %s\n"
86                    "\tIs NT6 DC that has some secrets:            %s\n"
87                    "\tIs NT6 DC that has all secrets:             %s\n"),
88                    (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
89                    (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
90                    (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
91                    (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
92                    (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
93                    (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
94                    (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
95                    (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
96                    (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
97                    (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
98                    (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
99                    (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
100
101
102         printf(_("Forest:\t\t\t%s\n"), reply.forest);
103         printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
104         printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
105
106         printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain);
107         printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
108
109         if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
110
111         printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
112         printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
113
114         d_printf(_("NT Version: %d\n"), reply.nt_version);
115         d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
116         d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
117
118         return 0;
119 }
120
121 /*
122   this implements the CLDAP based netlogon lookup requests
123   for finding the domain controller of a ADS domain
124 */
125 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
126 {
127         ADS_STRUCT *ads;
128         int ret;
129
130         if (c->display_usage) {
131                 d_printf("%s\n"
132                          "net ads lookup\n"
133                          "    %s",
134                          _("Usage:"),
135                          _("Find the ADS DC using CLDAP lookup.\n"));
136                 return 0;
137         }
138
139         if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
140                 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
141                 ads_destroy(&ads);
142                 return -1;
143         }
144
145         if (!ads->config.realm) {
146                 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
147                 ads->ldap.port = 389;
148         }
149
150         ret = net_ads_cldap_netlogon(c, ads);
151         ads_destroy(&ads);
152         return ret;
153 }
154
155
156
157 static int net_ads_info(struct net_context *c, int argc, const char **argv)
158 {
159         ADS_STRUCT *ads;
160         char addr[INET6_ADDRSTRLEN];
161
162         if (c->display_usage) {
163                 d_printf("%s\n"
164                          "net ads info\n"
165                          "    %s",
166                          _("Usage:"),
167                          _("Display information about an Active Directory "
168                            "server.\n"));
169                 return 0;
170         }
171
172         if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
173                 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
174                 return -1;
175         }
176
177         if (!ads || !ads->config.realm) {
178                 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
179                 ads_destroy(&ads);
180                 return -1;
181         }
182
183         /* Try to set the server's current time since we didn't do a full
184            TCP LDAP session initially */
185
186         if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
187                 d_fprintf( stderr, _("Failed to get server's current time!\n"));
188         }
189
190         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
191
192         d_printf(_("LDAP server: %s\n"), addr);
193         d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
194         d_printf(_("Realm: %s\n"), ads->config.realm);
195         d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
196         d_printf(_("LDAP port: %d\n"), ads->ldap.port);
197         d_printf(_("Server time: %s\n"),
198                          http_timestring(talloc_tos(), ads->config.current_time));
199
200         d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
201         d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
202
203         ads_destroy(&ads);
204         return 0;
205 }
206
207 static void use_in_memory_ccache(void) {
208         /* Use in-memory credentials cache so we do not interfere with
209          * existing credentials */
210         setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
211 }
212
213 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
214                                   uint32 auth_flags, ADS_STRUCT **ads_ret)
215 {
216         ADS_STRUCT *ads = NULL;
217         ADS_STATUS status;
218         bool need_password = false;
219         bool second_time = false;
220         char *cp;
221         const char *realm = NULL;
222         bool tried_closest_dc = false;
223
224         /* lp_realm() should be handled by a command line param,
225            However, the join requires that realm be set in smb.conf
226            and compares our realm with the remote server's so this is
227            ok until someone needs more flexibility */
228
229         *ads_ret = NULL;
230
231 retry_connect:
232         if (only_own_domain) {
233                 realm = lp_realm();
234         } else {
235                 realm = assume_own_realm(c);
236         }
237
238         ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
239
240         if (!c->opt_user_name) {
241                 c->opt_user_name = "administrator";
242         }
243
244         if (c->opt_user_specified) {
245                 need_password = true;
246         }
247
248 retry:
249         if (!c->opt_password && need_password && !c->opt_machine_pass) {
250                 c->opt_password = net_prompt_pass(c, c->opt_user_name);
251                 if (!c->opt_password) {
252                         ads_destroy(&ads);
253                         return ADS_ERROR(LDAP_NO_MEMORY);
254                 }
255         }
256
257         if (c->opt_password) {
258                 use_in_memory_ccache();
259                 SAFE_FREE(ads->auth.password);
260                 ads->auth.password = smb_xstrdup(c->opt_password);
261         }
262
263         ads->auth.flags |= auth_flags;
264         SAFE_FREE(ads->auth.user_name);
265         ads->auth.user_name = smb_xstrdup(c->opt_user_name);
266
267        /*
268         * If the username is of the form "name@realm",
269         * extract the realm and convert to upper case.
270         * This is only used to establish the connection.
271         */
272        if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
273                 *cp++ = '\0';
274                 SAFE_FREE(ads->auth.realm);
275                 ads->auth.realm = smb_xstrdup(cp);
276                 strupper_m(ads->auth.realm);
277        }
278
279         status = ads_connect(ads);
280
281         if (!ADS_ERR_OK(status)) {
282
283                 if (NT_STATUS_EQUAL(ads_ntstatus(status),
284                                     NT_STATUS_NO_LOGON_SERVERS)) {
285                         DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
286                         ads_destroy(&ads);
287                         return status;
288                 }
289
290                 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
291                         need_password = true;
292                         second_time = true;
293                         goto retry;
294                 } else {
295                         ads_destroy(&ads);
296                         return status;
297                 }
298         }
299
300         /* when contacting our own domain, make sure we use the closest DC.
301          * This is done by reconnecting to ADS because only the first call to
302          * ads_connect will give us our own sitename */
303
304         if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
305
306                 tried_closest_dc = true; /* avoid loop */
307
308                 if (!ads_closest_dc(ads)) {
309
310                         namecache_delete(ads->server.realm, 0x1C);
311                         namecache_delete(ads->server.workgroup, 0x1C);
312
313                         ads_destroy(&ads);
314                         ads = NULL;
315
316                         goto retry_connect;
317                 }
318         }
319
320         *ads_ret = ads;
321         return status;
322 }
323
324 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
325 {
326         return ads_startup_int(c, only_own_domain, 0, ads);
327 }
328
329 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
330 {
331         return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
332 }
333
334 /*
335   Check to see if connection can be made via ads.
336   ads_startup() stores the password in opt_password if it needs to so
337   that rpc or rap can use it without re-prompting.
338 */
339 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
340 {
341         ADS_STRUCT *ads;
342         ADS_STATUS status;
343
344         if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
345                 return -1;
346         }
347
348         ads->auth.flags |= ADS_AUTH_NO_BIND;
349
350         status = ads_connect(ads);
351         if ( !ADS_ERR_OK(status) ) {
352                 return -1;
353         }
354
355         ads_destroy(&ads);
356         return 0;
357 }
358
359 int net_ads_check_our_domain(struct net_context *c)
360 {
361         return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
362 }
363
364 int net_ads_check(struct net_context *c)
365 {
366         return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
367 }
368
369 /*
370    determine the netbios workgroup name for a domain
371  */
372 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
373 {
374         ADS_STRUCT *ads;
375         char addr[INET6_ADDRSTRLEN];
376         struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
377
378         if (c->display_usage) {
379                 d_printf  ("%s\n"
380                            "net ads workgroup\n"
381                            "    %s\n",
382                          _("Usage:"),
383                          _("Print the workgroup name"));
384                 return 0;
385         }
386
387         if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
388                 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
389                 return -1;
390         }
391
392         if (!ads->config.realm) {
393                 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
394                 ads->ldap.port = 389;
395         }
396
397         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
398         if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
399                 d_fprintf(stderr, _("CLDAP query failed!\n"));
400                 ads_destroy(&ads);
401                 return -1;
402         }
403
404         d_printf(_("Workgroup: %s\n"), reply.domain);
405
406         ads_destroy(&ads);
407
408         return 0;
409 }
410
411
412
413 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
414 {
415         char **disp_fields = (char **) data_area;
416
417         if (!field) { /* must be end of record */
418                 if (disp_fields[0]) {
419                         if (!strchr_m(disp_fields[0], '$')) {
420                                 if (disp_fields[1])
421                                         d_printf("%-21.21s %s\n",
422                                                disp_fields[0], disp_fields[1]);
423                                 else
424                                         d_printf("%s\n", disp_fields[0]);
425                         }
426                 }
427                 SAFE_FREE(disp_fields[0]);
428                 SAFE_FREE(disp_fields[1]);
429                 return true;
430         }
431         if (!values) /* must be new field, indicate string field */
432                 return true;
433         if (StrCaseCmp(field, "sAMAccountName") == 0) {
434                 disp_fields[0] = SMB_STRDUP((char *) values[0]);
435         }
436         if (StrCaseCmp(field, "description") == 0)
437                 disp_fields[1] = SMB_STRDUP((char *) values[0]);
438         return true;
439 }
440
441 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
442 {
443         return net_user_usage(c, argc, argv);
444 }
445
446 static int ads_user_add(struct net_context *c, int argc, const char **argv)
447 {
448         ADS_STRUCT *ads;
449         ADS_STATUS status;
450         char *upn, *userdn;
451         LDAPMessage *res=NULL;
452         int rc = -1;
453         char *ou_str = NULL;
454
455         if (argc < 1 || c->display_usage)
456                 return net_ads_user_usage(c, argc, argv);
457
458         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
459                 return -1;
460         }
461
462         status = ads_find_user_acct(ads, &res, argv[0]);
463
464         if (!ADS_ERR_OK(status)) {
465                 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
466                 goto done;
467         }
468
469         if (ads_count_replies(ads, res)) {
470                 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
471                           argv[0]);
472                 goto done;
473         }
474
475         if (c->opt_container) {
476                 ou_str = SMB_STRDUP(c->opt_container);
477         } else {
478                 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
479         }
480
481         status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
482
483         if (!ADS_ERR_OK(status)) {
484                 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
485                          ads_errstr(status));
486                 goto done;
487         }
488
489         /* if no password is to be set, we're done */
490         if (argc == 1) {
491                 d_printf(_("User %s added\n"), argv[0]);
492                 rc = 0;
493                 goto done;
494         }
495
496         /* try setting the password */
497         if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
498                 goto done;
499         }
500         status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
501                                        ads->auth.time_offset);
502         SAFE_FREE(upn);
503         if (ADS_ERR_OK(status)) {
504                 d_printf(_("User %s added\n"), argv[0]);
505                 rc = 0;
506                 goto done;
507         }
508
509         /* password didn't set, delete account */
510         d_fprintf(stderr, _("Could not add user %s. "
511                             "Error setting password %s\n"),
512                  argv[0], ads_errstr(status));
513         ads_msgfree(ads, res);
514         status=ads_find_user_acct(ads, &res, argv[0]);
515         if (ADS_ERR_OK(status)) {
516                 userdn = ads_get_dn(ads, talloc_tos(), res);
517                 ads_del_dn(ads, userdn);
518                 TALLOC_FREE(userdn);
519         }
520
521  done:
522         if (res)
523                 ads_msgfree(ads, res);
524         ads_destroy(&ads);
525         SAFE_FREE(ou_str);
526         return rc;
527 }
528
529 static int ads_user_info(struct net_context *c, int argc, const char **argv)
530 {
531         ADS_STRUCT *ads = NULL;
532         ADS_STATUS rc;
533         LDAPMessage *res = NULL;
534         TALLOC_CTX *frame;
535         int ret = 0;
536         wbcErr wbc_status;
537         const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
538         char *searchstring=NULL;
539         char **grouplist;
540         char *primary_group;
541         char *escaped_user;
542         DOM_SID primary_group_sid;
543         uint32_t group_rid;
544         enum wbcSidType type;
545
546         if (argc < 1 || c->display_usage) {
547                 return net_ads_user_usage(c, argc, argv);
548         }
549
550         frame = talloc_new(talloc_tos());
551         if (frame == NULL) {
552                 return -1;
553         }
554
555         escaped_user = escape_ldap_string(frame, argv[0]);
556         if (!escaped_user) {
557                 d_fprintf(stderr,
558                           _("ads_user_info: failed to escape user %s\n"),
559                           argv[0]);
560                 return -1;
561         }
562
563         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
564                 ret = -1;
565                 goto error;
566         }
567
568         if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
569                 ret =-1;
570                 goto error;
571         }
572         rc = ads_search(ads, &res, searchstring, attrs);
573         SAFE_FREE(searchstring);
574
575         if (!ADS_ERR_OK(rc)) {
576                 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
577                 ret = -1;
578                 goto error;
579         }
580
581         if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
582                 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
583                 ret = -1;
584                 goto error;
585         }
586
587         rc = ads_domain_sid(ads, &primary_group_sid);
588         if (!ADS_ERR_OK(rc)) {
589                 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
590                 ret = -1;
591                 goto error;
592         }
593
594         sid_append_rid(&primary_group_sid, group_rid);
595
596         wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
597                                   NULL, /* don't look up domain */
598                                   &primary_group,
599                                   &type);
600         if (!WBC_ERROR_IS_OK(wbc_status)) {
601                 d_fprintf(stderr, "wbcLookupSid: %s\n",
602                           wbcErrorString(wbc_status));
603                 ret = -1;
604                 goto error;
605         }
606
607         d_printf("%s\n", primary_group);
608
609         wbcFreeMemory(primary_group);
610
611         grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
612                                     (LDAPMessage *)res, "memberOf");
613
614         if (grouplist) {
615                 int i;
616                 char **groupname;
617                 for (i=0;grouplist[i];i++) {
618                         groupname = ldap_explode_dn(grouplist[i], 1);
619                         d_printf("%s\n", groupname[0]);
620                         ldap_value_free(groupname);
621                 }
622                 ldap_value_free(grouplist);
623         }
624
625 error:
626         if (res) ads_msgfree(ads, res);
627         if (ads) ads_destroy(&ads);
628         TALLOC_FREE(frame);
629         return ret;
630 }
631
632 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
633 {
634         ADS_STRUCT *ads;
635         ADS_STATUS rc;
636         LDAPMessage *res = NULL;
637         char *userdn;
638
639         if (argc < 1) {
640                 return net_ads_user_usage(c, argc, argv);
641         }
642
643         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
644                 return -1;
645         }
646
647         rc = ads_find_user_acct(ads, &res, argv[0]);
648         if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
649                 d_printf(_("User %s does not exist.\n"), argv[0]);
650                 ads_msgfree(ads, res);
651                 ads_destroy(&ads);
652                 return -1;
653         }
654         userdn = ads_get_dn(ads, talloc_tos(), res);
655         ads_msgfree(ads, res);
656         rc = ads_del_dn(ads, userdn);
657         TALLOC_FREE(userdn);
658         if (ADS_ERR_OK(rc)) {
659                 d_printf(_("User %s deleted\n"), argv[0]);
660                 ads_destroy(&ads);
661                 return 0;
662         }
663         d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
664                  ads_errstr(rc));
665         ads_destroy(&ads);
666         return -1;
667 }
668
669 int net_ads_user(struct net_context *c, int argc, const char **argv)
670 {
671         struct functable func[] = {
672                 {
673                         "add",
674                         ads_user_add,
675                         NET_TRANSPORT_ADS,
676                         N_("Add an AD user"),
677                         N_("net ads user add\n"
678                            "    Add an AD user")
679                 },
680                 {
681                         "info",
682                         ads_user_info,
683                         NET_TRANSPORT_ADS,
684                         N_("Display information about an AD user"),
685                         N_("net ads user info\n"
686                            "    Display information about an AD user")
687                 },
688                 {
689                         "delete",
690                         ads_user_delete,
691                         NET_TRANSPORT_ADS,
692                         N_("Delete an AD user"),
693                         N_("net ads user delete\n"
694                            "    Delete an AD user")
695                 },
696                 {NULL, NULL, 0, NULL, NULL}
697         };
698         ADS_STRUCT *ads;
699         ADS_STATUS rc;
700         const char *shortattrs[] = {"sAMAccountName", NULL};
701         const char *longattrs[] = {"sAMAccountName", "description", NULL};
702         char *disp_fields[2] = {NULL, NULL};
703
704         if (argc == 0) {
705                 if (c->display_usage) {
706                         d_printf(  "%s\n"
707                                    "net ads user\n"
708                                    "    %s\n",
709                                  _("Usage:"),
710                                  _("List AD users"));
711                         net_display_usage_from_functable(func);
712                         return 0;
713                 }
714
715                 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
716                         return -1;
717                 }
718
719                 if (c->opt_long_list_entries)
720                         d_printf(_("\nUser name             Comment"
721                                    "\n-----------------------------\n"));
722
723                 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
724                                           LDAP_SCOPE_SUBTREE,
725                                           "(objectCategory=user)",
726                                           c->opt_long_list_entries ? longattrs :
727                                           shortattrs, usergrp_display,
728                                           disp_fields);
729                 ads_destroy(&ads);
730                 return ADS_ERR_OK(rc) ? 0 : -1;
731         }
732
733         return net_run_function(c, argc, argv, "net ads user", func);
734 }
735
736 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
737 {
738         return net_group_usage(c, argc, argv);
739 }
740
741 static int ads_group_add(struct net_context *c, int argc, const char **argv)
742 {
743         ADS_STRUCT *ads;
744         ADS_STATUS status;
745         LDAPMessage *res=NULL;
746         int rc = -1;
747         char *ou_str = NULL;
748
749         if (argc < 1 || c->display_usage) {
750                 return net_ads_group_usage(c, argc, argv);
751         }
752
753         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
754                 return -1;
755         }
756
757         status = ads_find_user_acct(ads, &res, argv[0]);
758
759         if (!ADS_ERR_OK(status)) {
760                 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
761                 goto done;
762         }
763
764         if (ads_count_replies(ads, res)) {
765                 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
766                 goto done;
767         }
768
769         if (c->opt_container) {
770                 ou_str = SMB_STRDUP(c->opt_container);
771         } else {
772                 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
773         }
774
775         status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
776
777         if (ADS_ERR_OK(status)) {
778                 d_printf(_("Group %s added\n"), argv[0]);
779                 rc = 0;
780         } else {
781                 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
782                          ads_errstr(status));
783         }
784
785  done:
786         if (res)
787                 ads_msgfree(ads, res);
788         ads_destroy(&ads);
789         SAFE_FREE(ou_str);
790         return rc;
791 }
792
793 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
794 {
795         ADS_STRUCT *ads;
796         ADS_STATUS rc;
797         LDAPMessage *res = NULL;
798         char *groupdn;
799
800         if (argc < 1 || c->display_usage) {
801                 return net_ads_group_usage(c, argc, argv);
802         }
803
804         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
805                 return -1;
806         }
807
808         rc = ads_find_user_acct(ads, &res, argv[0]);
809         if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
810                 d_printf(_("Group %s does not exist.\n"), argv[0]);
811                 ads_msgfree(ads, res);
812                 ads_destroy(&ads);
813                 return -1;
814         }
815         groupdn = ads_get_dn(ads, talloc_tos(), res);
816         ads_msgfree(ads, res);
817         rc = ads_del_dn(ads, groupdn);
818         TALLOC_FREE(groupdn);
819         if (ADS_ERR_OK(rc)) {
820                 d_printf(_("Group %s deleted\n"), argv[0]);
821                 ads_destroy(&ads);
822                 return 0;
823         }
824         d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
825                  ads_errstr(rc));
826         ads_destroy(&ads);
827         return -1;
828 }
829
830 int net_ads_group(struct net_context *c, int argc, const char **argv)
831 {
832         struct functable func[] = {
833                 {
834                         "add",
835                         ads_group_add,
836                         NET_TRANSPORT_ADS,
837                         N_("Add an AD group"),
838                         N_("net ads group add\n"
839                            "    Add an AD group")
840                 },
841                 {
842                         "delete",
843                         ads_group_delete,
844                         NET_TRANSPORT_ADS,
845                         N_("Delete an AD group"),
846                         N_("net ads group delete\n"
847                            "    Delete an AD group")
848                 },
849                 {NULL, NULL, 0, NULL, NULL}
850         };
851         ADS_STRUCT *ads;
852         ADS_STATUS rc;
853         const char *shortattrs[] = {"sAMAccountName", NULL};
854         const char *longattrs[] = {"sAMAccountName", "description", NULL};
855         char *disp_fields[2] = {NULL, NULL};
856
857         if (argc == 0) {
858                 if (c->display_usage) {
859                         d_printf(  "%s\n"
860                                    "net ads group\n"
861                                    "    %s\n",
862                                  _("Usage:"),
863                                  _("List AD groups"));
864                         net_display_usage_from_functable(func);
865                         return 0;
866                 }
867
868                 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
869                         return -1;
870                 }
871
872                 if (c->opt_long_list_entries)
873                         d_printf(_("\nGroup name            Comment"
874                                    "\n-----------------------------\n"));
875                 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
876                                           LDAP_SCOPE_SUBTREE,
877                                           "(objectCategory=group)",
878                                           c->opt_long_list_entries ? longattrs :
879                                           shortattrs, usergrp_display,
880                                           disp_fields);
881
882                 ads_destroy(&ads);
883                 return ADS_ERR_OK(rc) ? 0 : -1;
884         }
885         return net_run_function(c, argc, argv, "net ads group", func);
886 }
887
888 static int net_ads_status(struct net_context *c, int argc, const char **argv)
889 {
890         ADS_STRUCT *ads;
891         ADS_STATUS rc;
892         LDAPMessage *res;
893
894         if (c->display_usage) {
895                 d_printf(  "%s\n"
896                            "net ads status\n"
897                            "    %s\n",
898                          _("Usage:"),
899                          _("Display machine account details"));
900                 return 0;
901         }
902
903         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
904                 return -1;
905         }
906
907         rc = ads_find_machine_acct(ads, &res, global_myname());
908         if (!ADS_ERR_OK(rc)) {
909                 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
910                 ads_destroy(&ads);
911                 return -1;
912         }
913
914         if (ads_count_replies(ads, res) == 0) {
915                 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
916                 ads_destroy(&ads);
917                 return -1;
918         }
919
920         ads_dump(ads, res);
921         ads_destroy(&ads);
922         return 0;
923 }
924
925 /*******************************************************************
926  Leave an AD domain.  Windows XP disables the machine account.
927  We'll try the same.  The old code would do an LDAP delete.
928  That only worked using the machine creds because added the machine
929  with full control to the computer object's ACL.
930 *******************************************************************/
931
932 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
933 {
934         TALLOC_CTX *ctx;
935         struct libnet_UnjoinCtx *r = NULL;
936         WERROR werr;
937
938         if (c->display_usage) {
939                 d_printf(  "%s\n"
940                            "net ads leave\n"
941                            "    %s\n",
942                          _("Usage:"),
943                          _("Leave an AD domain"));
944                 return 0;
945         }
946
947         if (!*lp_realm()) {
948                 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
949                 return -1;
950         }
951
952         if (!(ctx = talloc_init("net_ads_leave"))) {
953                 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
954                 return -1;
955         }
956
957         if (!c->opt_kerberos) {
958                 use_in_memory_ccache();
959         }
960
961         werr = libnet_init_UnjoinCtx(ctx, &r);
962         if (!W_ERROR_IS_OK(werr)) {
963                 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
964                 return -1;
965         }
966
967         r->in.debug             = true;
968         r->in.use_kerberos      = c->opt_kerberos;
969         r->in.dc_name           = c->opt_host;
970         r->in.domain_name       = lp_realm();
971         r->in.admin_account     = c->opt_user_name;
972         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
973         r->in.modify_config     = lp_config_backend_is_registry();
974
975         /* Try to delete it, but if that fails, disable it.  The
976            WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
977         r->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
978                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
979         r->in.delete_machine_account = true;
980
981         werr = libnet_Unjoin(ctx, r);
982         if (!W_ERROR_IS_OK(werr)) {
983                 d_printf(_("Failed to leave domain: %s\n"),
984                          r->out.error_string ? r->out.error_string :
985                          get_friendly_werror_msg(werr));
986                 goto done;
987         }
988
989         if (r->out.deleted_machine_account) {
990                 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
991                         r->in.machine_name, r->out.dns_domain_name);
992                 goto done;
993         }
994
995         /* We couldn't delete it - see if the disable succeeded. */
996         if (r->out.disabled_machine_account) {
997                 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
998                         r->in.machine_name, r->out.dns_domain_name);
999                 werr = WERR_OK;
1000                 goto done;
1001         }
1002
1003         /* Based on what we requseted, we shouldn't get here, but if
1004            we did, it means the secrets were removed, and therefore
1005            we have left the domain */
1006         d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1007                   r->in.machine_name, r->out.dns_domain_name);
1008
1009  done:
1010         TALLOC_FREE(r);
1011         TALLOC_FREE(ctx);
1012
1013         if (W_ERROR_IS_OK(werr)) {
1014                 return 0;
1015         }
1016
1017         return -1;
1018 }
1019
1020 static NTSTATUS net_ads_join_ok(struct net_context *c)
1021 {
1022         ADS_STRUCT *ads = NULL;
1023         ADS_STATUS status;
1024         fstring dc_name;
1025         struct sockaddr_storage dcip;
1026
1027         if (!secrets_init()) {
1028                 DEBUG(1,("Failed to initialise secrets database\n"));
1029                 return NT_STATUS_ACCESS_DENIED;
1030         }
1031
1032         net_use_krb_machine_account(c);
1033
1034         get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1035
1036         status = ads_startup(c, true, &ads);
1037         if (!ADS_ERR_OK(status)) {
1038                 return ads_ntstatus(status);
1039         }
1040
1041         ads_destroy(&ads);
1042         return NT_STATUS_OK;
1043 }
1044
1045 /*
1046   check that an existing join is OK
1047  */
1048 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1049 {
1050         NTSTATUS status;
1051         use_in_memory_ccache();
1052
1053         if (c->display_usage) {
1054                 d_printf(  "%s\n"
1055                            "net ads testjoin\n"
1056                            "    %s\n",
1057                          _("Usage:"),
1058                          _("Test if the existing join is ok"));
1059                 return 0;
1060         }
1061
1062         /* Display success or failure */
1063         status = net_ads_join_ok(c);
1064         if (!NT_STATUS_IS_OK(status)) {
1065                 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1066                         get_friendly_nt_error_msg(status));
1067                 return -1;
1068         }
1069
1070         printf(_("Join is OK\n"));
1071         return 0;
1072 }
1073
1074 /*******************************************************************
1075   Simple configu checks before beginning the join
1076  ********************************************************************/
1077
1078 static WERROR check_ads_config( void )
1079 {
1080         if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1081                 d_printf(_("Host is not configured as a member server.\n"));
1082                 return WERR_INVALID_DOMAIN_ROLE;
1083         }
1084
1085         if (strlen(global_myname()) > 15) {
1086                 d_printf(_("Our netbios name can be at most 15 chars long, "
1087                            "\"%s\" is %u chars long\n"), global_myname(),
1088                          (unsigned int)strlen(global_myname()));
1089                 return WERR_INVALID_COMPUTERNAME;
1090         }
1091
1092         if ( lp_security() == SEC_ADS && !*lp_realm()) {
1093                 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1094                           "join to succeed.\n"), get_dyn_CONFIGFILE());
1095                 return WERR_INVALID_PARAM;
1096         }
1097
1098         return WERR_OK;
1099 }
1100
1101 /*******************************************************************
1102  Send a DNS update request
1103 *******************************************************************/
1104
1105 #if defined(WITH_DNS_UPDATES)
1106 #include "dns.h"
1107 DNS_ERROR DoDNSUpdate(char *pszServerName,
1108                       const char *pszDomainName, const char *pszHostName,
1109                       const struct sockaddr_storage *sslist,
1110                       size_t num_addrs );
1111
1112 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1113                                         const char *machine_name,
1114                                         const struct sockaddr_storage *addrs,
1115                                         int num_addrs)
1116 {
1117         struct dns_rr_ns *nameservers = NULL;
1118         int ns_count = 0;
1119         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1120         DNS_ERROR dns_err;
1121         fstring dns_server;
1122         const char *dnsdomain = NULL;
1123         char *root_domain = NULL;
1124
1125         if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1126                 d_printf(_("No DNS domain configured for %s. "
1127                            "Unable to perform DNS Update.\n"), machine_name);
1128                 status = NT_STATUS_INVALID_PARAMETER;
1129                 goto done;
1130         }
1131         dnsdomain++;
1132
1133         status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1134         if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1135                 /* Child domains often do not have NS records.  Look
1136                    for the NS record for the forest root domain
1137                    (rootDomainNamingContext in therootDSE) */
1138
1139                 const char *rootname_attrs[] =  { "rootDomainNamingContext", NULL };
1140                 LDAPMessage *msg = NULL;
1141                 char *root_dn;
1142                 ADS_STATUS ads_status;
1143
1144                 if ( !ads->ldap.ld ) {
1145                         ads_status = ads_connect( ads );
1146                         if ( !ADS_ERR_OK(ads_status) ) {
1147                                 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1148                                 goto done;
1149                         }
1150                 }
1151
1152                 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1153                                        "(objectclass=*)", rootname_attrs, &msg);
1154                 if (!ADS_ERR_OK(ads_status)) {
1155                         goto done;
1156                 }
1157
1158                 root_dn = ads_pull_string(ads, ctx, msg,  "rootDomainNamingContext");
1159                 if ( !root_dn ) {
1160                         ads_msgfree( ads, msg );
1161                         goto done;
1162                 }
1163
1164                 root_domain = ads_build_domain( root_dn );
1165
1166                 /* cleanup */
1167                 ads_msgfree( ads, msg );
1168
1169                 /* try again for NS servers */
1170
1171                 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1172
1173                 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1174                         DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1175                          "realm\n", ads->config.realm));
1176                         goto done;
1177                 }
1178
1179                 dnsdomain = root_domain;
1180
1181         }
1182
1183         /* Now perform the dns update - we'll try non-secure and if we fail,
1184            we'll follow it up with a secure update */
1185
1186         fstrcpy( dns_server, nameservers[0].hostname );
1187
1188         dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1189         if (!ERR_DNS_IS_OK(dns_err)) {
1190                 status = NT_STATUS_UNSUCCESSFUL;
1191         }
1192
1193 done:
1194
1195         SAFE_FREE( root_domain );
1196
1197         return status;
1198 }
1199
1200 static NTSTATUS net_update_dns_ext(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1201                                    const char *hostname,
1202                                    struct sockaddr_storage *iplist,
1203                                    int num_addrs)
1204 {
1205         struct sockaddr_storage *iplist_alloc = NULL;
1206         fstring machine_name;
1207         NTSTATUS status;
1208
1209         if (hostname) {
1210                 fstrcpy(machine_name, hostname);
1211         } else {
1212                 name_to_fqdn( machine_name, global_myname() );
1213         }
1214         strlower_m( machine_name );
1215
1216         if (num_addrs == 0 || iplist == NULL) {
1217                 /*
1218                  * Get our ip address
1219                  * (not the 127.0.0.x address but a real ip address)
1220                  */
1221                 num_addrs = get_my_ip_address(&iplist_alloc);
1222                 if ( num_addrs <= 0 ) {
1223                         DEBUG(4, ("net_update_dns_ext: Failed to find my "
1224                                   "non-loopback IP addresses!\n"));
1225                         return NT_STATUS_INVALID_PARAMETER;
1226                 }
1227                 iplist = iplist_alloc;
1228         }
1229
1230         status = net_update_dns_internal(mem_ctx, ads, machine_name,
1231                                          iplist, num_addrs);
1232
1233         SAFE_FREE(iplist_alloc);
1234         return status;
1235 }
1236
1237 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1238 {
1239         NTSTATUS status;
1240
1241         status = net_update_dns_ext(mem_ctx, ads, hostname, NULL, 0);
1242         return status;
1243 }
1244 #endif
1245
1246
1247 /*******************************************************************
1248  ********************************************************************/
1249
1250 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1251 {
1252         d_printf(_("net ads join [options]\n"
1253                    "Valid options:\n"));
1254         d_printf(_("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n"
1255                    "                      The deault UPN is in the form host/netbiosname@REALM.\n"));
1256         d_printf(_("   createcomputer=OU  Precreate the computer account in a specific OU.\n"
1257                    "                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1258                    "                      E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1259                    "                      NB: A backslash '\\' is used as escape at multiple levels and may\n"
1260                    "                          need to be doubled or even quadrupled.  It is not used as a separator.\n"));
1261         d_printf(_("   osName=string      Set the operatingSystem attribute during the join.\n"));
1262         d_printf(_("   osVer=string       Set the operatingSystemVersion attribute during the join.\n"
1263                    "                      NB: osName and osVer must be specified together for either to take effect.\n"
1264                    "                          Also, the operatingSystemService attribute is also set when along with\n"
1265                    "                          the two other attributes.\n"));
1266
1267         return -1;
1268 }
1269
1270 /*******************************************************************
1271  ********************************************************************/
1272
1273 int net_ads_join(struct net_context *c, int argc, const char **argv)
1274 {
1275         TALLOC_CTX *ctx = NULL;
1276         struct libnet_JoinCtx *r = NULL;
1277         const char *domain = lp_realm();
1278         WERROR werr = WERR_SETUP_NOT_JOINED;
1279         bool createupn = false;
1280         const char *machineupn = NULL;
1281         const char *create_in_ou = NULL;
1282         int i;
1283         const char *os_name = NULL;
1284         const char *os_version = NULL;
1285         bool modify_config = lp_config_backend_is_registry();
1286
1287         if (c->display_usage)
1288                 return net_ads_join_usage(c, argc, argv);
1289
1290         if (!modify_config) {
1291
1292                 werr = check_ads_config();
1293                 if (!W_ERROR_IS_OK(werr)) {
1294                         d_fprintf(stderr, _("Invalid configuration.  Exiting....\n"));
1295                         goto fail;
1296                 }
1297         }
1298
1299         if (!(ctx = talloc_init("net_ads_join"))) {
1300                 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1301                 werr = WERR_NOMEM;
1302                 goto fail;
1303         }
1304
1305         if (!c->opt_kerberos) {
1306                 use_in_memory_ccache();
1307         }
1308
1309         werr = libnet_init_JoinCtx(ctx, &r);
1310         if (!W_ERROR_IS_OK(werr)) {
1311                 goto fail;
1312         }
1313
1314         /* process additional command line args */
1315
1316         for ( i=0; i<argc; i++ ) {
1317                 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1318                         createupn = true;
1319                         machineupn = get_string_param(argv[i]);
1320                 }
1321                 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1322                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1323                                 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1324                                 werr = WERR_INVALID_PARAM;
1325                                 goto fail;
1326                         }
1327                 }
1328                 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1329                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1330                                 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1331                                 werr = WERR_INVALID_PARAM;
1332                                 goto fail;
1333                         }
1334                 }
1335                 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1336                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1337                                 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1338                                 werr = WERR_INVALID_PARAM;
1339                                 goto fail;
1340                         }
1341                 }
1342                 else {
1343                         domain = argv[i];
1344                 }
1345         }
1346
1347         if (!*domain) {
1348                 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1349                 werr = WERR_INVALID_PARAM;
1350                 goto fail;
1351         }
1352
1353         /* Do the domain join here */
1354
1355         r->in.domain_name       = domain;
1356         r->in.create_upn        = createupn;
1357         r->in.upn               = machineupn;
1358         r->in.account_ou        = create_in_ou;
1359         r->in.os_name           = os_name;
1360         r->in.os_version        = os_version;
1361         r->in.dc_name           = c->opt_host;
1362         r->in.admin_account     = c->opt_user_name;
1363         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1364         r->in.debug             = true;
1365         r->in.use_kerberos      = c->opt_kerberos;
1366         r->in.modify_config     = modify_config;
1367         r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1368                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1369                                   WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1370
1371         werr = libnet_Join(ctx, r);
1372         if (!W_ERROR_IS_OK(werr)) {
1373                 goto fail;
1374         }
1375
1376         /* Check the short name of the domain */
1377
1378         if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1379                 d_printf(_("The workgroup in %s does not match the short\n"
1380                            "domain name obtained from the server.\n"
1381                            "Using the name [%s] from the server.\n"
1382                            "You should set \"workgroup = %s\" in %s.\n"),
1383                          get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1384                          r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1385         }
1386
1387         d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1388
1389         if (r->out.dns_domain_name) {
1390                 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1391                         r->out.dns_domain_name);
1392         } else {
1393                 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1394                         r->out.netbios_domain_name);
1395         }
1396
1397 #if defined(WITH_DNS_UPDATES)
1398         /*
1399          * In a clustered environment, don't do dynamic dns updates:
1400          * Registering the set of ip addresses that are assigned to
1401          * the interfaces of the node that performs the join does usually
1402          * not have the desired effect, since the local interfaces do not
1403          * carry the complete set of the cluster's public IP addresses.
1404          * And it can also contain internal addresses that should not
1405          * be visible to the outside at all.
1406          * In order to do dns updates in a clustererd setup, use
1407          * net ads dns register.
1408          */
1409         if (lp_clustering()) {
1410                 d_fprintf(stderr, _("Not doing automatic DNS update in a"
1411                                     "clustered setup.\n"));
1412                 goto done;
1413         }
1414
1415         if (r->out.domain_is_ad) {
1416                 /* We enter this block with user creds */
1417                 ADS_STRUCT *ads_dns = NULL;
1418
1419                 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1420                         /* kinit with the machine password */
1421
1422                         use_in_memory_ccache();
1423                         if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1424                                 goto fail;
1425                         }
1426                         ads_dns->auth.password = secrets_fetch_machine_password(
1427                                 r->out.netbios_domain_name, NULL, NULL );
1428                         ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1429                         strupper_m(ads_dns->auth.realm );
1430                         ads_kinit_password( ads_dns );
1431                 }
1432
1433                 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns, NULL)) ) {
1434                         d_fprintf( stderr, _("DNS update failed!\n") );
1435                 }
1436
1437                 /* exit from this block using machine creds */
1438                 ads_destroy(&ads_dns);
1439         }
1440 #endif
1441
1442 done:
1443         TALLOC_FREE(r);
1444         TALLOC_FREE( ctx );
1445
1446         return 0;
1447
1448 fail:
1449         /* issue an overall failure message at the end. */
1450         d_printf(_("Failed to join domain: %s\n"),
1451                 r && r->out.error_string ? r->out.error_string :
1452                 get_friendly_werror_msg(werr));
1453         TALLOC_FREE( ctx );
1454
1455         return -1;
1456 }
1457
1458 /*******************************************************************
1459  ********************************************************************/
1460
1461 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1462 {
1463 #if defined(WITH_DNS_UPDATES)
1464         ADS_STRUCT *ads;
1465         ADS_STATUS status;
1466         NTSTATUS ntstatus;
1467         TALLOC_CTX *ctx;
1468         const char *hostname = NULL;
1469         const char **addrs_list = NULL;
1470         struct sockaddr_storage *addrs = NULL;
1471         int num_addrs = 0;
1472         int count;
1473
1474 #ifdef DEVELOPER
1475         talloc_enable_leak_report();
1476 #endif
1477
1478         if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1479                 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1480                                     "detection of addresses in a clustered "
1481                                     "setup.\n"));
1482                 c->display_usage = true;
1483         }
1484
1485         if (c->display_usage) {
1486                 d_printf(  "%s\n"
1487                            "net ads dns register [hostname [IP [IP...]]]\n"
1488                            "    %s\n",
1489                          _("Usage:"),
1490                          _("Register hostname with DNS\n"));
1491                 return -1;
1492         }
1493
1494         if (!(ctx = talloc_init("net_ads_dns"))) {
1495                 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1496                 return -1;
1497         }
1498
1499         if (argc >= 1) {
1500                 hostname = argv[0];
1501         }
1502
1503         if (argc > 1) {
1504                 num_addrs = argc - 1;
1505                 addrs_list = &argv[1];
1506         } else if (lp_clustering()) {
1507                 addrs_list = lp_cluster_addresses();
1508                 num_addrs = str_list_length(addrs_list);
1509         }
1510
1511         if (num_addrs > 0) {
1512                 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1513                 if (addrs == NULL) {
1514                         d_fprintf(stderr, _("Error allocating memory!\n"));
1515                         talloc_free(ctx);
1516                         return -1;
1517                 }
1518         }
1519
1520         for (count = 0; count < num_addrs; count++) {
1521                 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1522                         d_fprintf(stderr, "%s '%s'.\n",
1523                                           _("Cannot interpret address"),
1524                                           addrs_list[count]);
1525                         talloc_free(ctx);
1526                         return -1;
1527                 }
1528         }
1529
1530         status = ads_startup(c, true, &ads);
1531         if ( !ADS_ERR_OK(status) ) {
1532                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1533                 TALLOC_FREE(ctx);
1534                 return -1;
1535         }
1536
1537         ntstatus = net_update_dns_ext(ctx, ads, hostname, addrs, num_addrs);
1538         if (!NT_STATUS_IS_OK(ntstatus)) {
1539                 d_fprintf( stderr, _("DNS update failed!\n") );
1540                 ads_destroy( &ads );
1541                 TALLOC_FREE( ctx );
1542                 return -1;
1543         }
1544
1545         d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1546
1547         ads_destroy(&ads);
1548         TALLOC_FREE( ctx );
1549
1550         return 0;
1551 #else
1552         d_fprintf(stderr,
1553                   _("DNS update support not enabled at compile time!\n"));
1554         return -1;
1555 #endif
1556 }
1557
1558 #if defined(WITH_DNS_UPDATES)
1559 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1560 #endif
1561
1562 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1563 {
1564 #if defined(WITH_DNS_UPDATES)
1565         DNS_ERROR err;
1566
1567 #ifdef DEVELOPER
1568         talloc_enable_leak_report();
1569 #endif
1570
1571         if (argc != 2 || c->display_usage) {
1572                 d_printf(  "%s\n"
1573                            "    %s\n"
1574                            "    %s\n",
1575                          _("Usage:"),
1576                          _("net ads dns gethostbyname <server> <name>\n"),
1577                          _("  Look up hostname from the AD\n"
1578                            "    server\tName server to use\n"
1579                            "    name\tName to look up\n"));
1580                 return -1;
1581         }
1582
1583         err = do_gethostbyname(argv[0], argv[1]);
1584
1585         d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1586 #endif
1587         return 0;
1588 }
1589
1590 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1591 {
1592         struct functable func[] = {
1593                 {
1594                         "register",
1595                         net_ads_dns_register,
1596                         NET_TRANSPORT_ADS,
1597                         N_("Add host dns entry to AD"),
1598                         N_("net ads dns register\n"
1599                            "    Add host dns entry to AD")
1600                 },
1601                 {
1602                         "gethostbyname",
1603                         net_ads_dns_gethostbyname,
1604                         NET_TRANSPORT_ADS,
1605                         N_("Look up host"),
1606                         N_("net ads dns gethostbyname\n"
1607                            "    Look up host")
1608                 },
1609                 {NULL, NULL, 0, NULL, NULL}
1610         };
1611
1612         return net_run_function(c, argc, argv, "net ads dns", func);
1613 }
1614
1615 /*******************************************************************
1616  ********************************************************************/
1617
1618 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1619 {
1620         d_printf(_(
1621 "\nnet ads printer search <printer>"
1622 "\n\tsearch for a printer in the directory\n"
1623 "\nnet ads printer info <printer> <server>"
1624 "\n\tlookup info in directory for printer on server"
1625 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1626 "\nnet ads printer publish <printername>"
1627 "\n\tpublish printer in directory"
1628 "\n\t(note: printer name is required)\n"
1629 "\nnet ads printer remove <printername>"
1630 "\n\tremove printer from directory"
1631 "\n\t(note: printer name is required)\n"));
1632         return -1;
1633 }
1634
1635 /*******************************************************************
1636  ********************************************************************/
1637
1638 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1639 {
1640         ADS_STRUCT *ads;
1641         ADS_STATUS rc;
1642         LDAPMessage *res = NULL;
1643
1644         if (c->display_usage) {
1645                 d_printf(  "%s\n"
1646                            "net ads printer search\n"
1647                            "    %s\n",
1648                          _("Usage:"),
1649                          _("List printers in the AD"));
1650                 return 0;
1651         }
1652
1653         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1654                 return -1;
1655         }
1656
1657         rc = ads_find_printers(ads, &res);
1658
1659         if (!ADS_ERR_OK(rc)) {
1660                 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1661                 ads_msgfree(ads, res);
1662                 ads_destroy(&ads);
1663                 return -1;
1664         }
1665
1666         if (ads_count_replies(ads, res) == 0) {
1667                 d_fprintf(stderr, _("No results found\n"));
1668                 ads_msgfree(ads, res);
1669                 ads_destroy(&ads);
1670                 return -1;
1671         }
1672
1673         ads_dump(ads, res);
1674         ads_msgfree(ads, res);
1675         ads_destroy(&ads);
1676         return 0;
1677 }
1678
1679 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1680 {
1681         ADS_STRUCT *ads;
1682         ADS_STATUS rc;
1683         const char *servername, *printername;
1684         LDAPMessage *res = NULL;
1685
1686         if (c->display_usage) {
1687                 d_printf("%s\n%s",
1688                          _("Usage:"),
1689                          _("net ads printer info [printername [servername]]\n"
1690                            "  Display printer info from AD\n"
1691                            "    printername\tPrinter name or wildcard\n"
1692                            "    servername\tName of the print server\n"));
1693                 return 0;
1694         }
1695
1696         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1697                 return -1;
1698         }
1699
1700         if (argc > 0) {
1701                 printername = argv[0];
1702         } else {
1703                 printername = "*";
1704         }
1705
1706         if (argc > 1) {
1707                 servername =  argv[1];
1708         } else {
1709                 servername = global_myname();
1710         }
1711
1712         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1713
1714         if (!ADS_ERR_OK(rc)) {
1715                 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1716                         servername, ads_errstr(rc));
1717                 ads_msgfree(ads, res);
1718                 ads_destroy(&ads);
1719                 return -1;
1720         }
1721
1722         if (ads_count_replies(ads, res) == 0) {
1723                 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1724                 ads_msgfree(ads, res);
1725                 ads_destroy(&ads);
1726                 return -1;
1727         }
1728
1729         ads_dump(ads, res);
1730         ads_msgfree(ads, res);
1731         ads_destroy(&ads);
1732
1733         return 0;
1734 }
1735
1736 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1737 {
1738         ADS_STRUCT *ads;
1739         ADS_STATUS rc;
1740         const char *servername, *printername;
1741         struct cli_state *cli = NULL;
1742         struct rpc_pipe_client *pipe_hnd = NULL;
1743         struct sockaddr_storage server_ss;
1744         NTSTATUS nt_status;
1745         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1746         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1747         char *prt_dn, *srv_dn, **srv_cn;
1748         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1749         LDAPMessage *res = NULL;
1750
1751         if (argc < 1 || c->display_usage) {
1752                 d_printf("%s\n%s",
1753                          _("Usage:"),
1754                          _("net ads printer publish <printername> [servername]\n"
1755                            "  Publish printer in AD\n"
1756                            "    printername\tName of the printer\n"
1757                            "    servername\tName of the print server\n"));
1758                 talloc_destroy(mem_ctx);
1759                 return -1;
1760         }
1761
1762         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1763                 talloc_destroy(mem_ctx);
1764                 return -1;
1765         }
1766
1767         printername = argv[0];
1768
1769         if (argc == 2) {
1770                 servername = argv[1];
1771         } else {
1772                 servername = global_myname();
1773         }
1774
1775         /* Get printer data from SPOOLSS */
1776
1777         resolve_name(servername, &server_ss, 0x20, false);
1778
1779         nt_status = cli_full_connection(&cli, global_myname(), servername,
1780                                         &server_ss, 0,
1781                                         "IPC$", "IPC",
1782                                         c->opt_user_name, c->opt_workgroup,
1783                                         c->opt_password ? c->opt_password : "",
1784                                         CLI_FULL_CONNECTION_USE_KERBEROS,
1785                                         Undefined, NULL);
1786
1787         if (NT_STATUS_IS_ERR(nt_status)) {
1788                 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1789                                     "obtain data for %s\n"),
1790                           servername, printername);
1791                 ads_destroy(&ads);
1792                 talloc_destroy(mem_ctx);
1793                 return -1;
1794         }
1795
1796         /* Publish on AD server */
1797
1798         ads_find_machine_acct(ads, &res, servername);
1799
1800         if (ads_count_replies(ads, res) == 0) {
1801                 d_fprintf(stderr, _("Could not find machine account for server "
1802                                     "%s\n"),
1803                          servername);
1804                 ads_destroy(&ads);
1805                 talloc_destroy(mem_ctx);
1806                 return -1;
1807         }
1808
1809         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1810         srv_cn = ldap_explode_dn(srv_dn, 1);
1811
1812         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1813         printername_escaped = escape_rdn_val_string_alloc(printername);
1814         if (!srv_cn_escaped || !printername_escaped) {
1815                 SAFE_FREE(srv_cn_escaped);
1816                 SAFE_FREE(printername_escaped);
1817                 d_fprintf(stderr, _("Internal error, out of memory!"));
1818                 ads_destroy(&ads);
1819                 talloc_destroy(mem_ctx);
1820                 return -1;
1821         }
1822
1823         if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1824                 SAFE_FREE(srv_cn_escaped);
1825                 SAFE_FREE(printername_escaped);
1826                 d_fprintf(stderr, _("Internal error, out of memory!"));
1827                 ads_destroy(&ads);
1828                 talloc_destroy(mem_ctx);
1829                 return -1;
1830         }
1831
1832         SAFE_FREE(srv_cn_escaped);
1833         SAFE_FREE(printername_escaped);
1834
1835         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1836         if (!NT_STATUS_IS_OK(nt_status)) {
1837                 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1838                          servername);
1839                 SAFE_FREE(prt_dn);
1840                 ads_destroy(&ads);
1841                 talloc_destroy(mem_ctx);
1842                 return -1;
1843         }
1844
1845         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1846                                                               printername))) {
1847                 SAFE_FREE(prt_dn);
1848                 ads_destroy(&ads);
1849                 talloc_destroy(mem_ctx);
1850                 return -1;
1851         }
1852
1853         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1854         if (!ADS_ERR_OK(rc)) {
1855                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1856                 SAFE_FREE(prt_dn);
1857                 ads_destroy(&ads);
1858                 talloc_destroy(mem_ctx);
1859                 return -1;
1860         }
1861
1862         d_printf("published printer\n");
1863         SAFE_FREE(prt_dn);
1864         ads_destroy(&ads);
1865         talloc_destroy(mem_ctx);
1866
1867         return 0;
1868 }
1869
1870 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1871 {
1872         ADS_STRUCT *ads;
1873         ADS_STATUS rc;
1874         const char *servername;
1875         char *prt_dn;
1876         LDAPMessage *res = NULL;
1877
1878         if (argc < 1 || c->display_usage) {
1879                 d_printf("%s\n%s",
1880                          _("Usage:"),
1881                          _("net ads printer remove <printername> [servername]\n"
1882                            "  Remove a printer from the AD\n"
1883                            "    printername\tName of the printer\n"
1884                            "    servername\tName of the print server\n"));
1885                 return -1;
1886         }
1887
1888         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1889                 return -1;
1890         }
1891
1892         if (argc > 1) {
1893                 servername = argv[1];
1894         } else {
1895                 servername = global_myname();
1896         }
1897
1898         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1899
1900         if (!ADS_ERR_OK(rc)) {
1901                 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1902                 ads_msgfree(ads, res);
1903                 ads_destroy(&ads);
1904                 return -1;
1905         }
1906
1907         if (ads_count_replies(ads, res) == 0) {
1908                 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1909                 ads_msgfree(ads, res);
1910                 ads_destroy(&ads);
1911                 return -1;
1912         }
1913
1914         prt_dn = ads_get_dn(ads, talloc_tos(), res);
1915         ads_msgfree(ads, res);
1916         rc = ads_del_dn(ads, prt_dn);
1917         TALLOC_FREE(prt_dn);
1918
1919         if (!ADS_ERR_OK(rc)) {
1920                 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1921                 ads_destroy(&ads);
1922                 return -1;
1923         }
1924
1925         ads_destroy(&ads);
1926         return 0;
1927 }
1928
1929 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1930 {
1931         struct functable func[] = {
1932                 {
1933                         "search",
1934                         net_ads_printer_search,
1935                         NET_TRANSPORT_ADS,
1936                         N_("Search for a printer"),
1937                         N_("net ads printer search\n"
1938                            "    Search for a printer")
1939                 },
1940                 {
1941                         "info",
1942                         net_ads_printer_info,
1943                         NET_TRANSPORT_ADS,
1944                         N_("Display printer information"),
1945                         N_("net ads printer info\n"
1946                            "    Display printer information")
1947                 },
1948                 {
1949                         "publish",
1950                         net_ads_printer_publish,
1951                         NET_TRANSPORT_ADS,
1952                         N_("Publish a printer"),
1953                         N_("net ads printer publish\n"
1954                            "    Publish a printer")
1955                 },
1956                 {
1957                         "remove",
1958                         net_ads_printer_remove,
1959                         NET_TRANSPORT_ADS,
1960                         N_("Delete a printer"),
1961                         N_("net ads printer remove\n"
1962                            "    Delete a printer")
1963                 },
1964                 {NULL, NULL, 0, NULL, NULL}
1965         };
1966
1967         return net_run_function(c, argc, argv, "net ads printer", func);
1968 }
1969
1970
1971 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1972 {
1973         ADS_STRUCT *ads;
1974         const char *auth_principal = c->opt_user_name;
1975         const char *auth_password = c->opt_password;
1976         char *realm = NULL;
1977         char *new_password = NULL;
1978         char *chr, *prompt;
1979         const char *user;
1980         ADS_STATUS ret;
1981
1982         if (c->display_usage) {
1983                 d_printf("%s\n%s",
1984                          _("Usage:"),
1985                          _("net ads password <username>\n"
1986                            "  Change password for user\n"
1987                            "    username\tName of user to change password for\n"));
1988                 return 0;
1989         }
1990
1991         if (c->opt_user_name == NULL || c->opt_password == NULL) {
1992                 d_fprintf(stderr, _("You must supply an administrator "
1993                                     "username/password\n"));
1994                 return -1;
1995         }
1996
1997         if (argc < 1) {
1998                 d_fprintf(stderr, _("ERROR: You must say which username to "
1999                                     "change password for\n"));
2000                 return -1;
2001         }
2002
2003         user = argv[0];
2004         if (!strchr_m(user, '@')) {
2005                 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2006                         return -1;
2007                 }
2008                 user = chr;
2009         }
2010
2011         use_in_memory_ccache();
2012         chr = strchr_m(auth_principal, '@');
2013         if (chr) {
2014                 realm = ++chr;
2015         } else {
2016                 realm = lp_realm();
2017         }
2018
2019         /* use the realm so we can eventually change passwords for users
2020         in realms other than default */
2021         if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2022                 return -1;
2023         }
2024
2025         /* we don't actually need a full connect, but it's the easy way to
2026                 fill in the KDC's addresss */
2027         ads_connect(ads);
2028
2029         if (!ads->config.realm) {
2030                 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2031                 ads_destroy(&ads);
2032                 return -1;
2033         }
2034
2035         if (argv[1]) {
2036                 new_password = (char *)argv[1];
2037         } else {
2038                 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2039                         return -1;
2040                 }
2041                 new_password = getpass(prompt);
2042                 free(prompt);
2043         }
2044
2045         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2046                                 auth_password, user, new_password, ads->auth.time_offset);
2047         if (!ADS_ERR_OK(ret)) {
2048                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2049                 ads_destroy(&ads);
2050                 return -1;
2051         }
2052
2053         d_printf(_("Password change for %s completed.\n"), user);
2054         ads_destroy(&ads);
2055
2056         return 0;
2057 }
2058
2059 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2060 {
2061         ADS_STRUCT *ads;
2062         char *host_principal;
2063         fstring my_name;
2064         ADS_STATUS ret;
2065
2066         if (c->display_usage) {
2067                 d_printf(  "%s\n"
2068                            "net ads changetrustpw\n"
2069                            "    %s\n",
2070                          _("Usage:"),
2071                          _("Change the machine account's trust password"));
2072                 return 0;
2073         }
2074
2075         if (!secrets_init()) {
2076                 DEBUG(1,("Failed to initialise secrets database\n"));
2077                 return -1;
2078         }
2079
2080         net_use_krb_machine_account(c);
2081
2082         use_in_memory_ccache();
2083
2084         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2085                 return -1;
2086         }
2087
2088         fstrcpy(my_name, global_myname());
2089         strlower_m(my_name);
2090         if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2091                 ads_destroy(&ads);
2092                 return -1;
2093         }
2094         d_printf(_("Changing password for principal: %s\n"), host_principal);
2095
2096         ret = ads_change_trust_account_password(ads, host_principal);
2097
2098         if (!ADS_ERR_OK(ret)) {
2099                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2100                 ads_destroy(&ads);
2101                 SAFE_FREE(host_principal);
2102                 return -1;
2103         }
2104
2105         d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2106
2107         if (USE_SYSTEM_KEYTAB) {
2108                 d_printf(_("Attempting to update system keytab with new password.\n"));
2109                 if (ads_keytab_create_default(ads)) {
2110                         d_printf(_("Failed to update system keytab.\n"));
2111                 }
2112         }
2113
2114         ads_destroy(&ads);
2115         SAFE_FREE(host_principal);
2116
2117         return 0;
2118 }
2119
2120 /*
2121   help for net ads search
2122 */
2123 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2124 {
2125         d_printf(_(
2126                 "\nnet ads search <expression> <attributes...>\n"
2127                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2128                 "The expression is a standard LDAP search expression, and the\n"
2129                 "attributes are a list of LDAP fields to show in the results.\n\n"
2130                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2131                 ));
2132         net_common_flags_usage(c, argc, argv);
2133         return -1;
2134 }
2135
2136
2137 /*
2138   general ADS search function. Useful in diagnosing problems in ADS
2139 */
2140 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2141 {
2142         ADS_STRUCT *ads;
2143         ADS_STATUS rc;
2144         const char *ldap_exp;
2145         const char **attrs;
2146         LDAPMessage *res = NULL;
2147
2148         if (argc < 1 || c->display_usage) {
2149                 return net_ads_search_usage(c, argc, argv);
2150         }
2151
2152         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2153                 return -1;
2154         }
2155
2156         ldap_exp = argv[0];
2157         attrs = (argv + 1);
2158
2159         rc = ads_do_search_all(ads, ads->config.bind_path,
2160                                LDAP_SCOPE_SUBTREE,
2161                                ldap_exp, attrs, &res);
2162         if (!ADS_ERR_OK(rc)) {
2163                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2164                 ads_destroy(&ads);
2165                 return -1;
2166         }
2167
2168         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2169
2170         /* dump the results */
2171         ads_dump(ads, res);
2172
2173         ads_msgfree(ads, res);
2174         ads_destroy(&ads);
2175
2176         return 0;
2177 }
2178
2179
2180 /*
2181   help for net ads search
2182 */
2183 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2184 {
2185         d_printf(_(
2186                 "\nnet ads dn <dn> <attributes...>\n"
2187                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2188                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2189                 "to show in the results\n\n"
2190                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2191                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2192                 ));
2193         net_common_flags_usage(c, argc, argv);
2194         return -1;
2195 }
2196
2197
2198 /*
2199   general ADS search function. Useful in diagnosing problems in ADS
2200 */
2201 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2202 {
2203         ADS_STRUCT *ads;
2204         ADS_STATUS rc;
2205         const char *dn;
2206         const char **attrs;
2207         LDAPMessage *res = NULL;
2208
2209         if (argc < 1 || c->display_usage) {
2210                 return net_ads_dn_usage(c, argc, argv);
2211         }
2212
2213         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2214                 return -1;
2215         }
2216
2217         dn = argv[0];
2218         attrs = (argv + 1);
2219
2220         rc = ads_do_search_all(ads, dn,
2221                                LDAP_SCOPE_BASE,
2222                                "(objectclass=*)", attrs, &res);
2223         if (!ADS_ERR_OK(rc)) {
2224                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2225                 ads_destroy(&ads);
2226                 return -1;
2227         }
2228
2229         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2230
2231         /* dump the results */
2232         ads_dump(ads, res);
2233
2234         ads_msgfree(ads, res);
2235         ads_destroy(&ads);
2236
2237         return 0;
2238 }
2239
2240 /*
2241   help for net ads sid search
2242 */
2243 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2244 {
2245         d_printf(_(
2246                 "\nnet ads sid <sid> <attributes...>\n"
2247                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2248                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2249                 "to show in the results\n\n"
2250                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2251                 ));
2252         net_common_flags_usage(c, argc, argv);
2253         return -1;
2254 }
2255
2256
2257 /*
2258   general ADS search function. Useful in diagnosing problems in ADS
2259 */
2260 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2261 {
2262         ADS_STRUCT *ads;
2263         ADS_STATUS rc;
2264         const char *sid_string;
2265         const char **attrs;
2266         LDAPMessage *res = NULL;
2267         DOM_SID sid;
2268
2269         if (argc < 1 || c->display_usage) {
2270                 return net_ads_sid_usage(c, argc, argv);
2271         }
2272
2273         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2274                 return -1;
2275         }
2276
2277         sid_string = argv[0];
2278         attrs = (argv + 1);
2279
2280         if (!string_to_sid(&sid, sid_string)) {
2281                 d_fprintf(stderr, _("could not convert sid\n"));
2282                 ads_destroy(&ads);
2283                 return -1;
2284         }
2285
2286         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2287         if (!ADS_ERR_OK(rc)) {
2288                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2289                 ads_destroy(&ads);
2290                 return -1;
2291         }
2292
2293         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2294
2295         /* dump the results */
2296         ads_dump(ads, res);
2297
2298         ads_msgfree(ads, res);
2299         ads_destroy(&ads);
2300
2301         return 0;
2302 }
2303
2304 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2305 {
2306         int ret;
2307         ADS_STRUCT *ads;
2308
2309         if (c->display_usage) {
2310                 d_printf(  "%s\n"
2311                            "net ads keytab flush\n"
2312                            "    %s\n",
2313                          _("Usage:"),
2314                          _("Delete the whole keytab"));
2315                 return 0;
2316         }
2317
2318         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2319                 return -1;
2320         }
2321         ret = ads_keytab_flush(ads);
2322         ads_destroy(&ads);
2323         return ret;
2324 }
2325
2326 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2327 {
2328         int i;
2329         int ret = 0;
2330         ADS_STRUCT *ads;
2331
2332         if (c->display_usage) {
2333                 d_printf("%s\n%s",
2334                          _("Usage:"),
2335                          _("net ads keytab add <principal> [principal ...]\n"
2336                            "  Add principals to local keytab\n"
2337                            "    principal\tKerberos principal to add to "
2338                            "keytab\n"));
2339                 return 0;
2340         }
2341
2342         d_printf(_("Processing principals to add...\n"));
2343         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2344                 return -1;
2345         }
2346         for (i = 0; i < argc; i++) {
2347                 ret |= ads_keytab_add_entry(ads, argv[i]);
2348         }
2349         ads_destroy(&ads);
2350         return ret;
2351 }
2352
2353 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2354 {
2355         ADS_STRUCT *ads;
2356         int ret;
2357
2358         if (c->display_usage) {
2359                 d_printf(  "%s\n"
2360                            "net ads keytab create\n"
2361                            "    %s\n",
2362                          _("Usage:"),
2363                          _("Create new default keytab"));
2364                 return 0;
2365         }
2366
2367         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2368                 return -1;
2369         }
2370         ret = ads_keytab_create_default(ads);
2371         ads_destroy(&ads);
2372         return ret;
2373 }
2374
2375 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2376 {
2377         const char *keytab = NULL;
2378
2379         if (c->display_usage) {
2380                 d_printf("%s\n%s",
2381                          _("Usage:"),
2382                          _("net ads keytab list [keytab]\n"
2383                            "  List a local keytab\n"
2384                            "    keytab\tKeytab to list\n"));
2385                 return 0;
2386         }
2387
2388         if (argc >= 1) {
2389                 keytab = argv[0];
2390         }
2391
2392         return ads_keytab_list(keytab);
2393 }
2394
2395
2396 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2397 {
2398         struct functable func[] = {
2399                 {
2400                         "add",
2401                         net_ads_keytab_add,
2402                         NET_TRANSPORT_ADS,
2403                         N_("Add a service principal"),
2404                         N_("net ads keytab add\n"
2405                            "    Add a service principal")
2406                 },
2407                 {
2408                         "create",
2409                         net_ads_keytab_create,
2410                         NET_TRANSPORT_ADS,
2411                         N_("Create a fresh keytab"),
2412                         N_("net ads keytab create\n"
2413                            "    Create a fresh keytab")
2414                 },
2415                 {
2416                         "flush",
2417                         net_ads_keytab_flush,
2418                         NET_TRANSPORT_ADS,
2419                         N_("Remove all keytab entries"),
2420                         N_("net ads keytab flush\n"
2421                            "    Remove all keytab entries")
2422                 },
2423                 {
2424                         "list",
2425                         net_ads_keytab_list,
2426                         NET_TRANSPORT_ADS,
2427                         N_("List a keytab"),
2428                         N_("net ads keytab list\n"
2429                            "    List a keytab")
2430                 },
2431                 {NULL, NULL, 0, NULL, NULL}
2432         };
2433
2434         if (!USE_KERBEROS_KEYTAB) {
2435                 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2436                     "keytab method to use keytab functions.\n"));
2437         }
2438
2439         return net_run_function(c, argc, argv, "net ads keytab", func);
2440 }
2441
2442 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2443 {
2444         int ret = -1;
2445
2446         if (c->display_usage) {
2447                 d_printf(  "%s\n"
2448                            "net ads kerberos renew\n"
2449                            "    %s\n",
2450                          _("Usage:"),
2451                          _("Renew TGT from existing credential cache"));
2452                 return 0;
2453         }
2454
2455         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2456         if (ret) {
2457                 d_printf(_("failed to renew kerberos ticket: %s\n"),
2458                         error_message(ret));
2459         }
2460         return ret;
2461 }
2462
2463 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2464 {
2465         struct PAC_DATA *pac = NULL;
2466         struct PAC_LOGON_INFO *info = NULL;
2467         TALLOC_CTX *mem_ctx = NULL;
2468         NTSTATUS status;
2469         int ret = -1;
2470         const char *impersonate_princ_s = NULL;
2471
2472         if (c->display_usage) {
2473                 d_printf(  "%s\n"
2474                            "net ads kerberos pac\n"
2475                            "    %s\n",
2476                          _("Usage:"),
2477                          _("Dump the Kerberos PAC"));
2478                 return 0;
2479         }
2480
2481         mem_ctx = talloc_init("net_ads_kerberos_pac");
2482         if (!mem_ctx) {
2483                 goto out;
2484         }
2485
2486         if (argc > 0) {
2487                 impersonate_princ_s = argv[0];
2488         }
2489
2490         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2491
2492         status = kerberos_return_pac(mem_ctx,
2493                                      c->opt_user_name,
2494                                      c->opt_password,
2495                                      0,
2496                                      NULL,
2497                                      NULL,
2498                                      NULL,
2499                                      true,
2500                                      true,
2501                                      2592000, /* one month */
2502                                      impersonate_princ_s,
2503                                      &pac);
2504         if (!NT_STATUS_IS_OK(status)) {
2505                 d_printf(_("failed to query kerberos PAC: %s\n"),
2506                         nt_errstr(status));
2507                 goto out;
2508         }
2509
2510         info = get_logon_info_from_pac(pac);
2511         if (info) {
2512                 const char *s;
2513                 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2514                 d_printf(_("The Pac: %s\n"), s);
2515         }
2516
2517         ret = 0;
2518  out:
2519         TALLOC_FREE(mem_ctx);
2520         return ret;
2521 }
2522
2523 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2524 {
2525         TALLOC_CTX *mem_ctx = NULL;
2526         int ret = -1;
2527         NTSTATUS status;
2528
2529         if (c->display_usage) {
2530                 d_printf(  "%s\n"
2531                            "net ads kerberos kinit\n"
2532                            "    %s\n",
2533                          _("Usage:"),
2534                          _("Get Ticket Granting Ticket (TGT) for the user"));
2535                 return 0;
2536         }
2537
2538         mem_ctx = talloc_init("net_ads_kerberos_kinit");
2539         if (!mem_ctx) {
2540                 goto out;
2541         }
2542
2543         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2544
2545         ret = kerberos_kinit_password_ext(c->opt_user_name,
2546                                           c->opt_password,
2547                                           0,
2548                                           NULL,
2549                                           NULL,
2550                                           NULL,
2551                                           true,
2552                                           true,
2553                                           2592000, /* one month */
2554                                           &status);
2555         if (ret) {
2556                 d_printf(_("failed to kinit password: %s\n"),
2557                         nt_errstr(status));
2558         }
2559  out:
2560         return ret;
2561 }
2562
2563 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2564 {
2565         struct functable func[] = {
2566                 {
2567                         "kinit",
2568                         net_ads_kerberos_kinit,
2569                         NET_TRANSPORT_ADS,
2570                         N_("Retrieve Ticket Granting Ticket (TGT)"),
2571                         N_("net ads kerberos kinit\n"
2572                            "    Receive Ticket Granting Ticket (TGT)")
2573                 },
2574                 {
2575                         "renew",
2576                         net_ads_kerberos_renew,
2577                         NET_TRANSPORT_ADS,
2578                         N_("Renew Ticket Granting Ticket from credential cache"),
2579                         N_("net ads kerberos renew\n"
2580                            "    Renew Ticket Granting Ticket (TGT) from "
2581                            "credential cache")
2582                 },
2583                 {
2584                         "pac",
2585                         net_ads_kerberos_pac,
2586                         NET_TRANSPORT_ADS,
2587                         N_("Dump Kerberos PAC"),
2588                         N_("net ads kerberos pac\n"
2589                            "    Dump Kerberos PAC")
2590                 },
2591                 {NULL, NULL, 0, NULL, NULL}
2592         };
2593
2594         return net_run_function(c, argc, argv, "net ads kerberos", func);
2595 }
2596
2597 int net_ads(struct net_context *c, int argc, const char **argv)
2598 {
2599         struct functable func[] = {
2600                 {
2601                         "info",
2602                         net_ads_info,
2603                         NET_TRANSPORT_ADS,
2604                         N_("Display details on remote ADS server"),
2605                         N_("net ads info\n"
2606                            "    Display details on remote ADS server")
2607                 },
2608                 {
2609                         "join",
2610                         net_ads_join,
2611                         NET_TRANSPORT_ADS,
2612                         N_("Join the local machine to ADS realm"),
2613                         N_("net ads join\n"
2614                            "    Join the local machine to ADS realm")
2615                 },
2616                 {
2617                         "testjoin",
2618                         net_ads_testjoin,
2619                         NET_TRANSPORT_ADS,
2620                         N_("Validate machine account"),
2621                         N_("net ads testjoin\n"
2622                            "    Validate machine account")
2623                 },
2624                 {
2625                         "leave",
2626                         net_ads_leave,
2627                         NET_TRANSPORT_ADS,
2628                         N_("Remove the local machine from ADS"),
2629                         N_("net ads leave\n"
2630                            "    Remove the local machine from ADS")
2631                 },
2632                 {
2633                         "status",
2634                         net_ads_status,
2635                         NET_TRANSPORT_ADS,
2636                         N_("Display machine account details"),
2637                         N_("net ads status\n"
2638                            "    Display machine account details")
2639                 },
2640                 {
2641                         "user",
2642                         net_ads_user,
2643                         NET_TRANSPORT_ADS,
2644                         N_("List/modify users"),
2645                         N_("net ads user\n"
2646                            "    List/modify users")
2647                 },
2648                 {
2649                         "group",
2650                         net_ads_group,
2651                         NET_TRANSPORT_ADS,
2652                         N_("List/modify groups"),
2653                         N_("net ads group\n"
2654                            "    List/modify groups")
2655                 },
2656                 {
2657                         "dns",
2658                         net_ads_dns,
2659                         NET_TRANSPORT_ADS,
2660                         N_("Issue dynamic DNS update"),
2661                         N_("net ads dns\n"
2662                            "    Issue dynamic DNS update")
2663                 },
2664                 {
2665                         "password",
2666                         net_ads_password,
2667                         NET_TRANSPORT_ADS,
2668                         N_("Change user passwords"),
2669                         N_("net ads password\n"
2670                            "    Change user passwords")
2671                 },
2672                 {
2673                         "changetrustpw",
2674                         net_ads_changetrustpw,
2675                         NET_TRANSPORT_ADS,
2676                         N_("Change trust account password"),
2677                         N_("net ads changetrustpw\n"
2678                            "    Change trust account password")
2679                 },
2680                 {
2681                         "printer",
2682                         net_ads_printer,
2683                         NET_TRANSPORT_ADS,
2684                         N_("List/modify printer entries"),
2685                         N_("net ads printer\n"
2686                            "    List/modify printer entries")
2687                 },
2688                 {
2689                         "search",
2690                         net_ads_search,
2691                         NET_TRANSPORT_ADS,
2692                         N_("Issue LDAP search using filter"),
2693                         N_("net ads search\n"
2694                            "    Issue LDAP search using filter")
2695                 },
2696                 {
2697                         "dn",
2698                         net_ads_dn,
2699                         NET_TRANSPORT_ADS,
2700                         N_("Issue LDAP search by DN"),
2701                         N_("net ads dn\n"
2702                            "    Issue LDAP search by DN")
2703                 },
2704                 {
2705                         "sid",
2706                         net_ads_sid,
2707                         NET_TRANSPORT_ADS,
2708                         N_("Issue LDAP search by SID"),
2709                         N_("net ads sid\n"
2710                            "    Issue LDAP search by SID")
2711                 },
2712                 {
2713                         "workgroup",
2714                         net_ads_workgroup,
2715                         NET_TRANSPORT_ADS,
2716                         N_("Display workgroup name"),
2717                         N_("net ads workgroup\n"
2718                            "    Display the workgroup name")
2719                 },
2720                 {
2721                         "lookup",
2722                         net_ads_lookup,
2723                         NET_TRANSPORT_ADS,
2724                         N_("Perfom CLDAP query on DC"),
2725                         N_("net ads lookup\n"
2726                            "    Find the ADS DC using CLDAP lookups")
2727                 },
2728                 {
2729                         "keytab",
2730                         net_ads_keytab,
2731                         NET_TRANSPORT_ADS,
2732                         N_("Manage local keytab file"),
2733                         N_("net ads keytab\n"
2734                            "    Manage local keytab file")
2735                 },
2736                 {
2737                         "gpo",
2738                         net_ads_gpo,
2739                         NET_TRANSPORT_ADS,
2740                         N_("Manage group policy objects"),
2741                         N_("net ads gpo\n"
2742                            "    Manage group policy objects")
2743                 },
2744                 {
2745                         "kerberos",
2746                         net_ads_kerberos,
2747                         NET_TRANSPORT_ADS,
2748                         N_("Manage kerberos keytab"),
2749                         N_("net ads kerberos\n"
2750                            "    Manage kerberos keytab")
2751                 },
2752                 {NULL, NULL, 0, NULL, NULL}
2753         };
2754
2755         return net_run_function(c, argc, argv, "net ads", func);
2756 }
2757
2758 #else
2759
2760 static int net_ads_noads(void)
2761 {
2762         d_fprintf(stderr, _("ADS support not compiled in\n"));
2763         return -1;
2764 }
2765
2766 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2767 {
2768         return net_ads_noads();
2769 }
2770
2771 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2772 {
2773         return net_ads_noads();
2774 }
2775
2776 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2777 {
2778         return net_ads_noads();
2779 }
2780
2781 int net_ads_join(struct net_context *c, int argc, const char **argv)
2782 {
2783         return net_ads_noads();
2784 }
2785
2786 int net_ads_user(struct net_context *c, int argc, const char **argv)
2787 {
2788         return net_ads_noads();
2789 }
2790
2791 int net_ads_group(struct net_context *c, int argc, const char **argv)
2792 {
2793         return net_ads_noads();
2794 }
2795
2796 /* this one shouldn't display a message */
2797 int net_ads_check(struct net_context *c)
2798 {
2799         return -1;
2800 }
2801
2802 int net_ads_check_our_domain(struct net_context *c)
2803 {
2804         return -1;
2805 }
2806
2807 int net_ads(struct net_context *c, int argc, const char **argv)
2808 {
2809         return net_ads_noads();
2810 }
2811
2812 #endif  /* WITH_ADS */