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