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