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