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