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