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