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