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