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