net ads: Fix typos.
[kamenim/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 nbt_cldap_netlogon_5 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.type) {
59         case SAMLOGON_AD_UNK_R:
60                 d_printf("SAMLOGON\n");
61                 break;
62         case SAMLOGON_AD_R:
63                 d_printf("SAMLOGON_USER\n");
64                 break;
65         default:
66                 d_printf("0x%x\n", reply.type);
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 nbt_cldap_netlogon_5 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         use_in_memory_ccache();
883
884         werr = libnet_init_UnjoinCtx(ctx, &r);
885         if (!W_ERROR_IS_OK(werr)) {
886                 d_fprintf(stderr, "Could not initialise unjoin context.\n");
887                 return -1;
888         }
889
890         r->in.debug             = true;
891         r->in.dc_name           = c->opt_host;
892         r->in.domain_name       = lp_realm();
893         r->in.admin_account     = c->opt_user_name;
894         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
895         r->in.modify_config     = lp_config_backend_is_registry();
896         r->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
897                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
898
899         werr = libnet_Unjoin(ctx, r);
900         if (!W_ERROR_IS_OK(werr)) {
901                 d_printf("Failed to leave domain: %s\n",
902                          r->out.error_string ? r->out.error_string :
903                          get_friendly_werror_msg(werr));
904                 goto done;
905         }
906
907         if (W_ERROR_IS_OK(werr)) {
908                 d_printf("Deleted account for '%s' in realm '%s'\n",
909                         r->in.machine_name, r->out.dns_domain_name);
910                 goto done;
911         }
912
913         /* We couldn't delete it - see if the disable succeeded. */
914         if (r->out.disabled_machine_account) {
915                 d_printf("Disabled account for '%s' in realm '%s'\n",
916                         r->in.machine_name, r->out.dns_domain_name);
917                 werr = WERR_OK;
918                 goto done;
919         }
920
921         d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
922                   r->in.machine_name, r->out.dns_domain_name);
923
924  done:
925         TALLOC_FREE(r);
926         TALLOC_FREE(ctx);
927
928         if (W_ERROR_IS_OK(werr)) {
929                 return 0;
930         }
931
932         return -1;
933 }
934
935 static NTSTATUS net_ads_join_ok(struct net_context *c)
936 {
937         ADS_STRUCT *ads = NULL;
938         ADS_STATUS status;
939
940         if (!secrets_init()) {
941                 DEBUG(1,("Failed to initialise secrets database\n"));
942                 return NT_STATUS_ACCESS_DENIED;
943         }
944
945         net_use_krb_machine_account(c);
946
947         status = ads_startup(c, true, &ads);
948         if (!ADS_ERR_OK(status)) {
949                 return ads_ntstatus(status);
950         }
951
952         ads_destroy(&ads);
953         return NT_STATUS_OK;
954 }
955
956 /*
957   check that an existing join is OK
958  */
959 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
960 {
961         NTSTATUS status;
962         use_in_memory_ccache();
963
964         if (c->display_usage) {
965                 d_printf("Usage:\n"
966                          "net ads testjoin\n"
967                          "    Test if the existing join is ok\n");
968                 return 0;
969         }
970
971         /* Display success or failure */
972         status = net_ads_join_ok(c);
973         if (!NT_STATUS_IS_OK(status)) {
974                 fprintf(stderr,"Join to domain is not valid: %s\n",
975                         get_friendly_nt_error_msg(status));
976                 return -1;
977         }
978
979         printf("Join is OK\n");
980         return 0;
981 }
982
983 /*******************************************************************
984   Simple configu checks before beginning the join
985  ********************************************************************/
986
987 static WERROR check_ads_config( void )
988 {
989         if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
990                 d_printf("Host is not configured as a member server.\n");
991                 return WERR_INVALID_DOMAIN_ROLE;
992         }
993
994         if (strlen(global_myname()) > 15) {
995                 d_printf("Our netbios name can be at most 15 chars long, "
996                          "\"%s\" is %u chars long\n", global_myname(),
997                          (unsigned int)strlen(global_myname()));
998                 return WERR_INVALID_COMPUTER_NAME;
999         }
1000
1001         if ( lp_security() == SEC_ADS && !*lp_realm()) {
1002                 d_fprintf(stderr, "realm must be set in in %s for ADS "
1003                         "join to succeed.\n", get_dyn_CONFIGFILE());
1004                 return WERR_INVALID_PARAM;
1005         }
1006
1007         return WERR_OK;
1008 }
1009
1010 /*******************************************************************
1011  Send a DNS update request
1012 *******************************************************************/
1013
1014 #if defined(WITH_DNS_UPDATES)
1015 #include "dns.h"
1016 DNS_ERROR DoDNSUpdate(char *pszServerName,
1017                       const char *pszDomainName, const char *pszHostName,
1018                       const struct sockaddr_storage *sslist,
1019                       size_t num_addrs );
1020
1021 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1022                                         const char *machine_name,
1023                                         const struct sockaddr_storage *addrs,
1024                                         int num_addrs)
1025 {
1026         struct dns_rr_ns *nameservers = NULL;
1027         int ns_count = 0;
1028         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1029         DNS_ERROR dns_err;
1030         fstring dns_server;
1031         const char *dnsdomain = NULL;
1032         char *root_domain = NULL;
1033
1034         if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1035                 d_printf("No DNS domain configured for %s. "
1036                          "Unable to perform DNS Update.\n", machine_name);
1037                 status = NT_STATUS_INVALID_PARAMETER;
1038                 goto done;
1039         }
1040         dnsdomain++;
1041
1042         status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1043         if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1044                 /* Child domains often do not have NS records.  Look
1045                    for the NS record for the forest root domain
1046                    (rootDomainNamingContext in therootDSE) */
1047
1048                 const char *rootname_attrs[] =  { "rootDomainNamingContext", NULL };
1049                 LDAPMessage *msg = NULL;
1050                 char *root_dn;
1051                 ADS_STATUS ads_status;
1052
1053                 if ( !ads->ldap.ld ) {
1054                         ads_status = ads_connect( ads );
1055                         if ( !ADS_ERR_OK(ads_status) ) {
1056                                 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1057                                 goto done;
1058                         }
1059                 }
1060
1061                 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1062                                        "(objectclass=*)", rootname_attrs, &msg);
1063                 if (!ADS_ERR_OK(ads_status)) {
1064                         goto done;
1065                 }
1066
1067                 root_dn = ads_pull_string(ads, ctx, msg,  "rootDomainNamingContext");
1068                 if ( !root_dn ) {
1069                         ads_msgfree( ads, msg );
1070                         goto done;
1071                 }
1072
1073                 root_domain = ads_build_domain( root_dn );
1074
1075                 /* cleanup */
1076                 ads_msgfree( ads, msg );
1077
1078                 /* try again for NS servers */
1079
1080                 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1081
1082                 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1083                         DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1084                          "realm\n", ads->config.realm));
1085                         goto done;
1086                 }
1087
1088                 dnsdomain = root_domain;
1089
1090         }
1091
1092         /* Now perform the dns update - we'll try non-secure and if we fail,
1093            we'll follow it up with a secure update */
1094
1095         fstrcpy( dns_server, nameservers[0].hostname );
1096
1097         dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1098         if (!ERR_DNS_IS_OK(dns_err)) {
1099                 status = NT_STATUS_UNSUCCESSFUL;
1100         }
1101
1102 done:
1103
1104         SAFE_FREE( root_domain );
1105
1106         return status;
1107 }
1108
1109 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1110 {
1111         int num_addrs;
1112         struct sockaddr_storage *iplist = NULL;
1113         fstring machine_name;
1114         NTSTATUS status;
1115
1116         name_to_fqdn( machine_name, global_myname() );
1117         strlower_m( machine_name );
1118
1119         /* Get our ip address (not the 127.0.0.x address but a real ip
1120          * address) */
1121
1122         num_addrs = get_my_ip_address( &iplist );
1123         if ( num_addrs <= 0 ) {
1124                 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1125                          "addresses!\n"));
1126                 return NT_STATUS_INVALID_PARAMETER;
1127         }
1128
1129         status = net_update_dns_internal(mem_ctx, ads, machine_name,
1130                                          iplist, num_addrs);
1131         SAFE_FREE( iplist );
1132         return status;
1133 }
1134 #endif
1135
1136
1137 /*******************************************************************
1138  ********************************************************************/
1139
1140 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1141 {
1142         d_printf("net ads join [options]\n");
1143         d_printf("Valid options:\n");
1144         d_printf("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n");
1145         d_printf("                      The deault UPN is in the form host/netbiosname@REALM.\n");
1146         d_printf("   createcomputer=OU  Precreate the computer account in a specific OU.\n");
1147         d_printf("                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1148         d_printf("                      E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1149         d_printf("                      NB: A backslash '\\' is used as escape at multiple levels and may\n");
1150         d_printf("                          need to be doubled or even quadrupled.  It is not used as a separator.\n");
1151         d_printf("   osName=string      Set the operatingSystem attribute during the join.\n");
1152         d_printf("   osVer=string       Set the operatingSystemVersion attribute during the join.\n");
1153         d_printf("                      NB: osName and osVer must be specified together for either to take effect.\n");
1154         d_printf("                          Also, the operatingSystemService attribute is also set when along with\n");
1155         d_printf("                          the two other attributes.\n");
1156
1157         return -1;
1158 }
1159
1160 /*******************************************************************
1161  ********************************************************************/
1162
1163 int net_ads_join(struct net_context *c, int argc, const char **argv)
1164 {
1165         TALLOC_CTX *ctx = NULL;
1166         struct libnet_JoinCtx *r = NULL;
1167         const char *domain = lp_realm();
1168         WERROR werr = WERR_SETUP_NOT_JOINED;
1169         bool createupn = false;
1170         const char *machineupn = NULL;
1171         const char *create_in_ou = NULL;
1172         int i;
1173         const char *os_name = NULL;
1174         const char *os_version = NULL;
1175         bool modify_config = lp_config_backend_is_registry();
1176
1177         if (c->display_usage)
1178                 return net_ads_join_usage(c, argc, argv);
1179
1180         if (!modify_config) {
1181
1182                 werr = check_ads_config();
1183                 if (!W_ERROR_IS_OK(werr)) {
1184                         d_fprintf(stderr, "Invalid configuration.  Exiting....\n");
1185                         goto fail;
1186                 }
1187         }
1188
1189         if (!(ctx = talloc_init("net_ads_join"))) {
1190                 d_fprintf(stderr, "Could not initialise talloc context.\n");
1191                 werr = WERR_NOMEM;
1192                 goto fail;
1193         }
1194
1195         use_in_memory_ccache();
1196
1197         werr = libnet_init_JoinCtx(ctx, &r);
1198         if (!W_ERROR_IS_OK(werr)) {
1199                 goto fail;
1200         }
1201
1202         /* process additional command line args */
1203
1204         for ( i=0; i<argc; i++ ) {
1205                 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1206                         createupn = true;
1207                         machineupn = get_string_param(argv[i]);
1208                 }
1209                 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1210                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1211                                 d_fprintf(stderr, "Please supply a valid OU path.\n");
1212                                 werr = WERR_INVALID_PARAM;
1213                                 goto fail;
1214                         }
1215                 }
1216                 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1217                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1218                                 d_fprintf(stderr, "Please supply a operating system name.\n");
1219                                 werr = WERR_INVALID_PARAM;
1220                                 goto fail;
1221                         }
1222                 }
1223                 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1224                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1225                                 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1226                                 werr = WERR_INVALID_PARAM;
1227                                 goto fail;
1228                         }
1229                 }
1230                 else {
1231                         domain = argv[i];
1232                 }
1233         }
1234
1235         if (!*domain) {
1236                 d_fprintf(stderr, "Please supply a valid domain name\n");
1237                 werr = WERR_INVALID_PARAM;
1238                 goto fail;
1239         }
1240
1241         /* Do the domain join here */
1242
1243         r->in.domain_name       = domain;
1244         r->in.create_upn        = createupn;
1245         r->in.upn               = machineupn;
1246         r->in.account_ou        = create_in_ou;
1247         r->in.os_name           = os_name;
1248         r->in.os_version        = os_version;
1249         r->in.dc_name           = c->opt_host;
1250         r->in.admin_account     = c->opt_user_name;
1251         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1252         r->in.debug             = true;
1253         r->in.modify_config     = modify_config;
1254         r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1255                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1256                                   WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1257
1258         werr = libnet_Join(ctx, r);
1259         if (!W_ERROR_IS_OK(werr)) {
1260                 goto fail;
1261         }
1262
1263         /* Check the short name of the domain */
1264
1265         if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1266                 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1267                 d_printf("domain name obtained from the server.\n");
1268                 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1269                 d_printf("You should set \"workgroup = %s\" in %s.\n",
1270                          r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1271         }
1272
1273         d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1274
1275         if (r->out.dns_domain_name) {
1276                 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1277                         r->out.dns_domain_name);
1278         } else {
1279                 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1280                         r->out.netbios_domain_name);
1281         }
1282
1283 #if defined(WITH_DNS_UPDATES)
1284         if (r->out.domain_is_ad) {
1285                 /* We enter this block with user creds */
1286                 ADS_STRUCT *ads_dns = NULL;
1287
1288                 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1289                         /* kinit with the machine password */
1290
1291                         use_in_memory_ccache();
1292                         asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1293                         ads_dns->auth.password = secrets_fetch_machine_password(
1294                                 r->out.netbios_domain_name, NULL, NULL );
1295                         ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1296                         strupper_m(ads_dns->auth.realm );
1297                         ads_kinit_password( ads_dns );
1298                 }
1299
1300                 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1301                         d_fprintf( stderr, "DNS update failed!\n" );
1302                 }
1303
1304                 /* exit from this block using machine creds */
1305                 ads_destroy(&ads_dns);
1306         }
1307 #endif
1308         TALLOC_FREE(r);
1309         TALLOC_FREE( ctx );
1310
1311         return 0;
1312
1313 fail:
1314         /* issue an overall failure message at the end. */
1315         d_printf("Failed to join domain: %s\n",
1316                 r && r->out.error_string ? r->out.error_string :
1317                 get_friendly_werror_msg(werr));
1318         TALLOC_FREE( ctx );
1319
1320         return -1;
1321 }
1322
1323 /*******************************************************************
1324  ********************************************************************/
1325
1326 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1327 {
1328 #if defined(WITH_DNS_UPDATES)
1329         ADS_STRUCT *ads;
1330         ADS_STATUS status;
1331         TALLOC_CTX *ctx;
1332
1333 #ifdef DEVELOPER
1334         talloc_enable_leak_report();
1335 #endif
1336
1337         if (argc > 0 || c->display_usage) {
1338                 d_printf("Usage:\n"
1339                          "net ads dns register\n"
1340                          "    Register hostname with DNS\n");
1341                 return -1;
1342         }
1343
1344         if (!(ctx = talloc_init("net_ads_dns"))) {
1345                 d_fprintf(stderr, "Could not initialise talloc context\n");
1346                 return -1;
1347         }
1348
1349         status = ads_startup(c, true, &ads);
1350         if ( !ADS_ERR_OK(status) ) {
1351                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1352                 TALLOC_FREE(ctx);
1353                 return -1;
1354         }
1355
1356         if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1357                 d_fprintf( stderr, "DNS update failed!\n" );
1358                 ads_destroy( &ads );
1359                 TALLOC_FREE( ctx );
1360                 return -1;
1361         }
1362
1363         d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1364
1365         ads_destroy(&ads);
1366         TALLOC_FREE( ctx );
1367
1368         return 0;
1369 #else
1370         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1371         return -1;
1372 #endif
1373 }
1374
1375 #if defined(WITH_DNS_UPDATES)
1376 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1377 #endif
1378
1379 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1380 {
1381 #if defined(WITH_DNS_UPDATES)
1382         DNS_ERROR err;
1383
1384 #ifdef DEVELOPER
1385         talloc_enable_leak_report();
1386 #endif
1387
1388         if (argc != 2 || c->display_usage) {
1389                 d_printf("Usage:\n"
1390                          "net ads dns gethostbyname <server> <name>\n"
1391                          "  Look up hostname from the AD\n"
1392                          "    server\tName server to use\n"
1393                          "    name\tName to look up\n");
1394                 return -1;
1395         }
1396
1397         err = do_gethostbyname(argv[0], argv[1]);
1398
1399         d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1400 #endif
1401         return 0;
1402 }
1403
1404 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1405 {
1406         struct functable func[] = {
1407                 {
1408                         "register",
1409                         net_ads_dns_register,
1410                         NET_TRANSPORT_ADS,
1411                         "Add host dns entry to AD",
1412                         "net ads dns register\n"
1413                         "    Add host dns entry to AD"
1414                 },
1415                 {
1416                         "gethostbyname",
1417                         net_ads_dns_gethostbyname,
1418                         NET_TRANSPORT_ADS,
1419                         "Look up host",
1420                         "net ads dns gethostbyname\n"
1421                         "    Look up host"
1422                 },
1423                 {NULL, NULL, 0, NULL, NULL}
1424         };
1425
1426         return net_run_function(c, argc, argv, "net ads dns", func);
1427 }
1428
1429 /*******************************************************************
1430  ********************************************************************/
1431
1432 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1433 {
1434         d_printf(
1435 "\nnet ads printer search <printer>"
1436 "\n\tsearch for a printer in the directory\n"
1437 "\nnet ads printer info <printer> <server>"
1438 "\n\tlookup info in directory for printer on server"
1439 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1440 "\nnet ads printer publish <printername>"
1441 "\n\tpublish printer in directory"
1442 "\n\t(note: printer name is required)\n"
1443 "\nnet ads printer remove <printername>"
1444 "\n\tremove printer from directory"
1445 "\n\t(note: printer name is required)\n");
1446         return -1;
1447 }
1448
1449 /*******************************************************************
1450  ********************************************************************/
1451
1452 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1453 {
1454         ADS_STRUCT *ads;
1455         ADS_STATUS rc;
1456         LDAPMessage *res = NULL;
1457
1458         if (c->display_usage) {
1459                 d_printf("Usage:\n"
1460                          "net ads printer search\n"
1461                          "    List printers in the AD\n");
1462                 return 0;
1463         }
1464
1465         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1466                 return -1;
1467         }
1468
1469         rc = ads_find_printers(ads, &res);
1470
1471         if (!ADS_ERR_OK(rc)) {
1472                 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1473                 ads_msgfree(ads, res);
1474                 ads_destroy(&ads);
1475                 return -1;
1476         }
1477
1478         if (ads_count_replies(ads, res) == 0) {
1479                 d_fprintf(stderr, "No results found\n");
1480                 ads_msgfree(ads, res);
1481                 ads_destroy(&ads);
1482                 return -1;
1483         }
1484
1485         ads_dump(ads, res);
1486         ads_msgfree(ads, res);
1487         ads_destroy(&ads);
1488         return 0;
1489 }
1490
1491 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1492 {
1493         ADS_STRUCT *ads;
1494         ADS_STATUS rc;
1495         const char *servername, *printername;
1496         LDAPMessage *res = NULL;
1497
1498         if (c->display_usage) {
1499                 d_printf("Usage:\n"
1500                          "net ads printer info [printername [servername]]\n"
1501                          "  Display printer info from AD\n"
1502                          "    printername\tPrinter name or wildcard\n"
1503                          "    servername\tName of the print server\n");
1504                 return 0;
1505         }
1506
1507         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1508                 return -1;
1509         }
1510
1511         if (argc > 0) {
1512                 printername = argv[0];
1513         } else {
1514                 printername = "*";
1515         }
1516
1517         if (argc > 1) {
1518                 servername =  argv[1];
1519         } else {
1520                 servername = global_myname();
1521         }
1522
1523         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1524
1525         if (!ADS_ERR_OK(rc)) {
1526                 d_fprintf(stderr, "Server '%s' not found: %s\n",
1527                         servername, ads_errstr(rc));
1528                 ads_msgfree(ads, res);
1529                 ads_destroy(&ads);
1530                 return -1;
1531         }
1532
1533         if (ads_count_replies(ads, res) == 0) {
1534                 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1535                 ads_msgfree(ads, res);
1536                 ads_destroy(&ads);
1537                 return -1;
1538         }
1539
1540         ads_dump(ads, res);
1541         ads_msgfree(ads, res);
1542         ads_destroy(&ads);
1543
1544         return 0;
1545 }
1546
1547 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1548 {
1549         ADS_STRUCT *ads;
1550         ADS_STATUS rc;
1551         const char *servername, *printername;
1552         struct cli_state *cli;
1553         struct rpc_pipe_client *pipe_hnd;
1554         struct sockaddr_storage server_ss;
1555         NTSTATUS nt_status;
1556         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1557         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1558         char *prt_dn, *srv_dn, **srv_cn;
1559         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1560         LDAPMessage *res = NULL;
1561
1562         if (argc < 1 || c->display_usage) {
1563                 d_printf("Usage:\n"
1564                          "net ads printer publish <printername> [servername]\n"
1565                          "  Publish printer in AD\n"
1566                          "    printername\tName of the printer\n"
1567                          "    servername\tName of the print server\n");
1568                 talloc_destroy(mem_ctx);
1569                 return -1;
1570         }
1571
1572         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1573                 talloc_destroy(mem_ctx);
1574                 return -1;
1575         }
1576
1577         printername = argv[0];
1578
1579         if (argc == 2) {
1580                 servername = argv[1];
1581         } else {
1582                 servername = global_myname();
1583         }
1584
1585         /* Get printer data from SPOOLSS */
1586
1587         resolve_name(servername, &server_ss, 0x20);
1588
1589         nt_status = cli_full_connection(&cli, global_myname(), servername,
1590                                         &server_ss, 0,
1591                                         "IPC$", "IPC",
1592                                         c->opt_user_name, c->opt_workgroup,
1593                                         c->opt_password ? c->opt_password : "",
1594                                         CLI_FULL_CONNECTION_USE_KERBEROS,
1595                                         Undefined, NULL);
1596
1597         if (NT_STATUS_IS_ERR(nt_status)) {
1598                 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1599                          "for %s\n", servername, printername);
1600                 ads_destroy(&ads);
1601                 talloc_destroy(mem_ctx);
1602                 return -1;
1603         }
1604
1605         /* Publish on AD server */
1606
1607         ads_find_machine_acct(ads, &res, servername);
1608
1609         if (ads_count_replies(ads, res) == 0) {
1610                 d_fprintf(stderr, "Could not find machine account for server %s\n", 
1611                          servername);
1612                 ads_destroy(&ads);
1613                 talloc_destroy(mem_ctx);
1614                 return -1;
1615         }
1616
1617         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1618         srv_cn = ldap_explode_dn(srv_dn, 1);
1619
1620         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1621         printername_escaped = escape_rdn_val_string_alloc(printername);
1622         if (!srv_cn_escaped || !printername_escaped) {
1623                 SAFE_FREE(srv_cn_escaped);
1624                 SAFE_FREE(printername_escaped);
1625                 d_fprintf(stderr, "Internal error, out of memory!");
1626                 ads_destroy(&ads);
1627                 talloc_destroy(mem_ctx);
1628                 return -1;
1629         }
1630
1631         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1632
1633         SAFE_FREE(srv_cn_escaped);
1634         SAFE_FREE(printername_escaped);
1635
1636         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1637         if (!pipe_hnd) {
1638                 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1639                          servername);
1640                 SAFE_FREE(prt_dn);
1641                 ads_destroy(&ads);
1642                 talloc_destroy(mem_ctx);
1643                 return -1;
1644         }
1645
1646         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1647                                                               printername))) {
1648                 SAFE_FREE(prt_dn);
1649                 ads_destroy(&ads);
1650                 talloc_destroy(mem_ctx);
1651                 return -1;
1652         }
1653
1654         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1655         if (!ADS_ERR_OK(rc)) {
1656                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1657                 SAFE_FREE(prt_dn);
1658                 ads_destroy(&ads);
1659                 talloc_destroy(mem_ctx);
1660                 return -1;
1661         }
1662
1663         d_printf("published printer\n");
1664         SAFE_FREE(prt_dn);
1665         ads_destroy(&ads);
1666         talloc_destroy(mem_ctx);
1667
1668         return 0;
1669 }
1670
1671 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1672 {
1673         ADS_STRUCT *ads;
1674         ADS_STATUS rc;
1675         const char *servername;
1676         char *prt_dn;
1677         LDAPMessage *res = NULL;
1678
1679         if (argc < 1 || c->display_usage) {
1680                 d_printf("Usage:\n"
1681                          "net ads printer remove <printername> [servername]\n"
1682                          "  Remove a printer from the AD\n"
1683                          "    printername\tName of the printer\n"
1684                          "    servername\tName of the print server\n");
1685                 return -1;
1686         }
1687
1688         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1689                 return -1;
1690         }
1691
1692         if (argc > 1) {
1693                 servername = argv[1];
1694         } else {
1695                 servername = global_myname();
1696         }
1697
1698         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1699
1700         if (!ADS_ERR_OK(rc)) {
1701                 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1702                 ads_msgfree(ads, res);
1703                 ads_destroy(&ads);
1704                 return -1;
1705         }
1706
1707         if (ads_count_replies(ads, res) == 0) {
1708                 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1709                 ads_msgfree(ads, res);
1710                 ads_destroy(&ads);
1711                 return -1;
1712         }
1713
1714         prt_dn = ads_get_dn(ads, res);
1715         ads_msgfree(ads, res);
1716         rc = ads_del_dn(ads, prt_dn);
1717         ads_memfree(ads, prt_dn);
1718
1719         if (!ADS_ERR_OK(rc)) {
1720                 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1721                 ads_destroy(&ads);
1722                 return -1;
1723         }
1724
1725         ads_destroy(&ads);
1726         return 0;
1727 }
1728
1729 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1730 {
1731         struct functable func[] = {
1732                 {
1733                         "search",
1734                         net_ads_printer_search,
1735                         NET_TRANSPORT_ADS,
1736                         "Search for a printer",
1737                         "net ads printer search\n"
1738                         "    Search for a printer"
1739                 },
1740                 {
1741                         "info",
1742                         net_ads_printer_info,
1743                         NET_TRANSPORT_ADS,
1744                         "Display printer information",
1745                         "net ads printer info\n"
1746                         "    Display printer information"
1747                 },
1748                 {
1749                         "publish",
1750                         net_ads_printer_publish,
1751                         NET_TRANSPORT_ADS,
1752                         "Publish a printer",
1753                         "net ads printer publish\n"
1754                         "    Publish a printer"
1755                 },
1756                 {
1757                         "remove",
1758                         net_ads_printer_remove,
1759                         NET_TRANSPORT_ADS,
1760                         "Delete a printer",
1761                         "net ads printer remove\n"
1762                         "    Delete a printer"
1763                 },
1764                 {NULL, NULL, 0, NULL, NULL}
1765         };
1766
1767         return net_run_function(c, argc, argv, "net ads printer", func);
1768 }
1769
1770
1771 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1772 {
1773         ADS_STRUCT *ads;
1774         const char *auth_principal = c->opt_user_name;
1775         const char *auth_password = c->opt_password;
1776         char *realm = NULL;
1777         char *new_password = NULL;
1778         char *chr, *prompt;
1779         const char *user;
1780         ADS_STATUS ret;
1781
1782         if (c->display_usage) {
1783                 d_printf("Usage:\n"
1784                          "net ads password <username>\n"
1785                          "  Change password for user\n"
1786                          "    username\tName of user to change password for\n");
1787                 return 0;
1788         }
1789
1790         if (c->opt_user_name == NULL || c->opt_password == NULL) {
1791                 d_fprintf(stderr, "You must supply an administrator username/password\n");
1792                 return -1;
1793         }
1794
1795         if (argc < 1) {
1796                 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1797                 return -1;
1798         }
1799
1800         user = argv[0];
1801         if (!strchr_m(user, '@')) {
1802                 asprintf(&chr, "%s@%s", argv[0], lp_realm());
1803                 user = chr;
1804         }
1805
1806         use_in_memory_ccache();
1807         chr = strchr_m(auth_principal, '@');
1808         if (chr) {
1809                 realm = ++chr;
1810         } else {
1811                 realm = lp_realm();
1812         }
1813
1814         /* use the realm so we can eventually change passwords for users
1815         in realms other than default */
1816         if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1817                 return -1;
1818         }
1819
1820         /* we don't actually need a full connect, but it's the easy way to
1821                 fill in the KDC's addresss */
1822         ads_connect(ads);
1823
1824         if (!ads->config.realm) {
1825                 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1826                 return -1;
1827         }
1828
1829         if (argv[1]) {
1830                 new_password = (char *)argv[1];
1831         } else {
1832                 asprintf(&prompt, "Enter new password for %s:", user);
1833                 new_password = getpass(prompt);
1834                 free(prompt);
1835         }
1836
1837         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1838                                 auth_password, user, new_password, ads->auth.time_offset);
1839         if (!ADS_ERR_OK(ret)) {
1840                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1841                 ads_destroy(&ads);
1842                 return -1;
1843         }
1844
1845         d_printf("Password change for %s completed.\n", user);
1846         ads_destroy(&ads);
1847
1848         return 0;
1849 }
1850
1851 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1852 {
1853         ADS_STRUCT *ads;
1854         char *host_principal;
1855         fstring my_name;
1856         ADS_STATUS ret;
1857
1858         if (c->display_usage) {
1859                 d_printf("Usage:\n"
1860                          "net ads changetrustpw\n"
1861                          "    Change the machine account's trust password\n");
1862                 return 0;
1863         }
1864
1865         if (!secrets_init()) {
1866                 DEBUG(1,("Failed to initialise secrets database\n"));
1867                 return -1;
1868         }
1869
1870         net_use_krb_machine_account(c);
1871
1872         use_in_memory_ccache();
1873
1874         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1875                 return -1;
1876         }
1877
1878         fstrcpy(my_name, global_myname());
1879         strlower_m(my_name);
1880         asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1881         d_printf("Changing password for principal: %s\n", host_principal);
1882
1883         ret = ads_change_trust_account_password(ads, host_principal);
1884
1885         if (!ADS_ERR_OK(ret)) {
1886                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1887                 ads_destroy(&ads);
1888                 SAFE_FREE(host_principal);
1889                 return -1;
1890         }
1891
1892         d_printf("Password change for principal %s succeeded.\n", host_principal);
1893
1894         if (lp_use_kerberos_keytab()) {
1895                 d_printf("Attempting to update system keytab with new password.\n");
1896                 if (ads_keytab_create_default(ads)) {
1897                         d_printf("Failed to update system keytab.\n");
1898                 }
1899         }
1900
1901         ads_destroy(&ads);
1902         SAFE_FREE(host_principal);
1903
1904         return 0;
1905 }
1906
1907 /*
1908   help for net ads search
1909 */
1910 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1911 {
1912         d_printf(
1913                 "\nnet ads search <expression> <attributes...>\n"
1914                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1915                 "The expression is a standard LDAP search expression, and the\n"
1916                 "attributes are a list of LDAP fields to show in the results.\n\n"
1917                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1918                 );
1919         net_common_flags_usage(c, argc, argv);
1920         return -1;
1921 }
1922
1923
1924 /*
1925   general ADS search function. Useful in diagnosing problems in ADS
1926 */
1927 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1928 {
1929         ADS_STRUCT *ads;
1930         ADS_STATUS rc;
1931         const char *ldap_exp;
1932         const char **attrs;
1933         LDAPMessage *res = NULL;
1934
1935         if (argc < 1 || c->display_usage) {
1936                 return net_ads_search_usage(c, argc, argv);
1937         }
1938
1939         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1940                 return -1;
1941         }
1942
1943         ldap_exp = argv[0];
1944         attrs = (argv + 1);
1945
1946         rc = ads_do_search_all(ads, ads->config.bind_path,
1947                                LDAP_SCOPE_SUBTREE,
1948                                ldap_exp, attrs, &res);
1949         if (!ADS_ERR_OK(rc)) {
1950                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1951                 ads_destroy(&ads);
1952                 return -1;
1953         }
1954
1955         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1956
1957         /* dump the results */
1958         ads_dump(ads, res);
1959
1960         ads_msgfree(ads, res);
1961         ads_destroy(&ads);
1962
1963         return 0;
1964 }
1965
1966
1967 /*
1968   help for net ads search
1969 */
1970 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
1971 {
1972         d_printf(
1973                 "\nnet ads dn <dn> <attributes...>\n"
1974                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1975                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
1976                 "to show in the results\n\n"
1977                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1978                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1979                 );
1980         net_common_flags_usage(c, argc, argv);
1981         return -1;
1982 }
1983
1984
1985 /*
1986   general ADS search function. Useful in diagnosing problems in ADS
1987 */
1988 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
1989 {
1990         ADS_STRUCT *ads;
1991         ADS_STATUS rc;
1992         const char *dn;
1993         const char **attrs;
1994         LDAPMessage *res = NULL;
1995
1996         if (argc < 1 || c->display_usage) {
1997                 return net_ads_dn_usage(c, argc, argv);
1998         }
1999
2000         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2001                 return -1;
2002         }
2003
2004         dn = argv[0];
2005         attrs = (argv + 1);
2006
2007         rc = ads_do_search_all(ads, dn,
2008                                LDAP_SCOPE_BASE,
2009                                "(objectclass=*)", attrs, &res);
2010         if (!ADS_ERR_OK(rc)) {
2011                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2012                 ads_destroy(&ads);
2013                 return -1;
2014         }
2015
2016         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2017
2018         /* dump the results */
2019         ads_dump(ads, res);
2020
2021         ads_msgfree(ads, res);
2022         ads_destroy(&ads);
2023
2024         return 0;
2025 }
2026
2027 /*
2028   help for net ads sid search
2029 */
2030 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2031 {
2032         d_printf(
2033                 "\nnet ads sid <sid> <attributes...>\n"
2034                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2035                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2036                 "to show in the results\n\n"
2037                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2038                 );
2039         net_common_flags_usage(c, argc, argv);
2040         return -1;
2041 }
2042
2043
2044 /*
2045   general ADS search function. Useful in diagnosing problems in ADS
2046 */
2047 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2048 {
2049         ADS_STRUCT *ads;
2050         ADS_STATUS rc;
2051         const char *sid_string;
2052         const char **attrs;
2053         LDAPMessage *res = NULL;
2054         DOM_SID sid;
2055
2056         if (argc < 1 || c->display_usage) {
2057                 return net_ads_sid_usage(c, argc, argv);
2058         }
2059
2060         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2061                 return -1;
2062         }
2063
2064         sid_string = argv[0];
2065         attrs = (argv + 1);
2066
2067         if (!string_to_sid(&sid, sid_string)) {
2068                 d_fprintf(stderr, "could not convert sid\n");
2069                 ads_destroy(&ads);
2070                 return -1;
2071         }
2072
2073         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2074         if (!ADS_ERR_OK(rc)) {
2075                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2076                 ads_destroy(&ads);
2077                 return -1;
2078         }
2079
2080         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2081
2082         /* dump the results */
2083         ads_dump(ads, res);
2084
2085         ads_msgfree(ads, res);
2086         ads_destroy(&ads);
2087
2088         return 0;
2089 }
2090
2091 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2092 {
2093         int ret;
2094         ADS_STRUCT *ads;
2095
2096         if (c->display_usage) {
2097                 d_printf("Usage:\n"
2098                          "net ads keytab flush\n"
2099                          "    Delete the whole keytab\n");
2100                 return 0;
2101         }
2102
2103         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2104                 return -1;
2105         }
2106         ret = ads_keytab_flush(ads);
2107         ads_destroy(&ads);
2108         return ret;
2109 }
2110
2111 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2112 {
2113         int i;
2114         int ret = 0;
2115         ADS_STRUCT *ads;
2116
2117         if (c->display_usage) {
2118                 d_printf("Usage:\n"
2119                          "net ads keytab add <principal> [principal ...]\n"
2120                          "  Add principals to local keytab\n"
2121                          "    principal\tKerberos principal to add to "
2122                          "keytab\n");
2123                 return 0;
2124         }
2125
2126         d_printf("Processing principals to add...\n");
2127         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2128                 return -1;
2129         }
2130         for (i = 0; i < argc; i++) {
2131                 ret |= ads_keytab_add_entry(ads, argv[i]);
2132         }
2133         ads_destroy(&ads);
2134         return ret;
2135 }
2136
2137 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2138 {
2139         ADS_STRUCT *ads;
2140         int ret;
2141
2142         if (c->display_usage) {
2143                 d_printf("Usage:\n"
2144                          "net ads keytab create\n"
2145                          "    Create new default keytab\n");
2146                 return 0;
2147         }
2148
2149         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2150                 return -1;
2151         }
2152         ret = ads_keytab_create_default(ads);
2153         ads_destroy(&ads);
2154         return ret;
2155 }
2156
2157 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2158 {
2159         const char *keytab = NULL;
2160
2161         if (c->display_usage) {
2162                 d_printf("Usage:\n"
2163                          "net ads keytab list [keytab]\n"
2164                          "  List a local keytab\n"
2165                          "    keytab\tKeytab to list\n");
2166                 return 0;
2167         }
2168
2169         if (argc >= 1) {
2170                 keytab = argv[0];
2171         }
2172
2173         return ads_keytab_list(keytab);
2174 }
2175
2176
2177 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2178 {
2179         struct functable func[] = {
2180                 {
2181                         "add",
2182                         net_ads_keytab_add,
2183                         NET_TRANSPORT_ADS,
2184                         "Add a service principal",
2185                         "net ads keytab add\n"
2186                         "    Add a service principal"
2187                 },
2188                 {
2189                         "create",
2190                         net_ads_keytab_create,
2191                         NET_TRANSPORT_ADS,
2192                         "Create a fresh keytab",
2193                         "net ads keytab create\n"
2194                         "    Create a fresh keytab"
2195                 },
2196                 {
2197                         "flush",
2198                         net_ads_keytab_flush,
2199                         NET_TRANSPORT_ADS,
2200                         "Remove all keytab entries",
2201                         "net ads keytab flush\n"
2202                         "    Remove all keytab entries"
2203                 },
2204                 {
2205                         "list",
2206                         net_ads_keytab_list,
2207                         NET_TRANSPORT_ADS,
2208                         "List a keytab",
2209                         "net ads keytab list\n"
2210                         "    List a keytab"
2211                 },
2212                 {NULL, NULL, 0, NULL, NULL}
2213         };
2214
2215         if (!lp_use_kerberos_keytab()) {
2216                 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2217 use keytab functions.\n");
2218         }
2219
2220         return net_run_function(c, argc, argv, "net ads keytab", func);
2221 }
2222
2223 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2224 {
2225         int ret = -1;
2226
2227         if (c->display_usage) {
2228                 d_printf("Usage:\n"
2229                          "net ads kerberos renew\n"
2230                          "    Renew TGT from existing credential cache\n");
2231                 return 0;
2232         }
2233
2234         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2235         if (ret) {
2236                 d_printf("failed to renew kerberos ticket: %s\n",
2237                         error_message(ret));
2238         }
2239         return ret;
2240 }
2241
2242 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2243 {
2244         struct PAC_DATA *pac = NULL;
2245         struct PAC_LOGON_INFO *info = NULL;
2246         TALLOC_CTX *mem_ctx = NULL;
2247         NTSTATUS status;
2248         int ret = -1;
2249
2250         if (c->display_usage) {
2251                 d_printf("Usage:\n"
2252                          "net ads kerberos pac\n"
2253                          "    Dump the Kerberos PAC\n");
2254                 return 0;
2255         }
2256
2257         mem_ctx = talloc_init("net_ads_kerberos_pac");
2258         if (!mem_ctx) {
2259                 goto out;
2260         }
2261
2262         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2263
2264         status = kerberos_return_pac(mem_ctx,
2265                                      c->opt_user_name,
2266                                      c->opt_password,
2267                                      0,
2268                                      NULL,
2269                                      NULL,
2270                                      NULL,
2271                                      true,
2272                                      true,
2273                                      2592000, /* one month */
2274                                      &pac);
2275         if (!NT_STATUS_IS_OK(status)) {
2276                 d_printf("failed to query kerberos PAC: %s\n",
2277                         nt_errstr(status));
2278                 goto out;
2279         }
2280
2281         info = get_logon_info_from_pac(pac);
2282         if (info) {
2283                 const char *s;
2284                 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2285                 d_printf("The Pac: %s\n", s);
2286         }
2287
2288         ret = 0;
2289  out:
2290         TALLOC_FREE(mem_ctx);
2291         return ret;
2292 }
2293
2294 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2295 {
2296         TALLOC_CTX *mem_ctx = NULL;
2297         int ret = -1;
2298         NTSTATUS status;
2299
2300         if (c->display_usage) {
2301                 d_printf("Usage:\n"
2302                          "net ads kerberos kinit\n"
2303                          "    Get Ticket Granting Ticket (TGT) for the user\n");
2304                 return 0;
2305         }
2306
2307         mem_ctx = talloc_init("net_ads_kerberos_kinit");
2308         if (!mem_ctx) {
2309                 goto out;
2310         }
2311
2312         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2313
2314         ret = kerberos_kinit_password_ext(c->opt_user_name,
2315                                           c->opt_password,
2316                                           0,
2317                                           NULL,
2318                                           NULL,
2319                                           NULL,
2320                                           true,
2321                                           true,
2322                                           2592000, /* one month */
2323                                           &status);
2324         if (ret) {
2325                 d_printf("failed to kinit password: %s\n",
2326                         nt_errstr(status));
2327         }
2328  out:
2329         return ret;
2330 }
2331
2332 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2333 {
2334         struct functable func[] = {
2335                 {
2336                         "kinit",
2337                         net_ads_kerberos_kinit,
2338                         NET_TRANSPORT_ADS,
2339                         "Retrieve Ticket Granting Ticket (TGT)",
2340                         "net ads kerberos kinit\n"
2341                         "    Receive Ticket Granting Ticket (TGT)"
2342                 },
2343                 {
2344                         "renew",
2345                         net_ads_kerberos_renew,
2346                         NET_TRANSPORT_ADS,
2347                         "Renew Ticket Granting Ticket from credential cache"
2348                         "net ads kerberos renew\n"
2349                         "    Renew Ticket Granting Ticket from credential cache"
2350                 },
2351                 {
2352                         "pac",
2353                         net_ads_kerberos_pac,
2354                         NET_TRANSPORT_ADS,
2355                         "Dump Kerberos PAC",
2356                         "net ads kerberos pac\n"
2357                         "    Dump Kerberos PAC"
2358                 },
2359                 {NULL, NULL, 0, NULL, NULL}
2360         };
2361
2362         return net_run_function(c, argc, argv, "net ads kerberos", func);
2363 }
2364
2365 int net_ads(struct net_context *c, int argc, const char **argv)
2366 {
2367         struct functable func[] = {
2368                 {
2369                         "info",
2370                         net_ads_info,
2371                         NET_TRANSPORT_ADS,
2372                         "Display details on remote ADS server",
2373                         "net ads info\n"
2374                         "    Display details on remote ADS server"
2375                 },
2376                 {
2377                         "join",
2378                         net_ads_join,
2379                         NET_TRANSPORT_ADS,
2380                         "Join the local machine to ADS realm",
2381                         "net ads join\n"
2382                         "    Join the local machine to ADS realm"
2383                 },
2384                 {
2385                         "testjoin",
2386                         net_ads_testjoin,
2387                         NET_TRANSPORT_ADS,
2388                         "Validate machine account",
2389                         "net ads testjoin\n"
2390                         "    Validate machine account"
2391                 },
2392                 {
2393                         "leave",
2394                         net_ads_leave,
2395                         NET_TRANSPORT_ADS,
2396                         "Remove the local machine from ADS",
2397                         "net ads leave\n"
2398                         "    Remove the local machine from ADS"
2399                 },
2400                 {
2401                         "status",
2402                         net_ads_status,
2403                         NET_TRANSPORT_ADS,
2404                         "Display machine account details",
2405                         "net ads status\n"
2406                         "    Display machine account details"
2407                 },
2408                 {
2409                         "user",
2410                         net_ads_user,
2411                         NET_TRANSPORT_ADS,
2412                         "List/modify users",
2413                         "net ads user\n"
2414                         "    List/modify users"
2415                 },
2416                 {
2417                         "group",
2418                         net_ads_group,
2419                         NET_TRANSPORT_ADS,
2420                         "List/modify groups",
2421                         "net ads group\n"
2422                         "    List/modify groups"
2423                 },
2424                 {
2425                         "dns",
2426                         net_ads_dns,
2427                         NET_TRANSPORT_ADS,
2428                         "Issue dynamic DNS update",
2429                         "net ads dns\n"
2430                         "    Issue dynamic DNS update"
2431                 },
2432                 {
2433                         "password",
2434                         net_ads_password,
2435                         NET_TRANSPORT_ADS,
2436                         "Change user passwords",
2437                         "net ads password\n"
2438                         "    Change user passwords"
2439                 },
2440                 {
2441                         "changetrustpw",
2442                         net_ads_changetrustpw,
2443                         NET_TRANSPORT_ADS,
2444                         "Change trust account password",
2445                         "net ads changetrustpw\n"
2446                         "    Change trust account password"
2447                 },
2448                 {
2449                         "printer",
2450                         net_ads_printer,
2451                         NET_TRANSPORT_ADS,
2452                         "List/modify printer entries",
2453                         "net ads printer\n"
2454                         "    List/modify printer entries"
2455                 },
2456                 {
2457                         "search",
2458                         net_ads_search,
2459                         NET_TRANSPORT_ADS,
2460                         "Issue LDAP search using filter",
2461                         "net ads search\n"
2462                         "    Issue LDAP search using filter"
2463                 },
2464                 {
2465                         "dn",
2466                         net_ads_dn,
2467                         NET_TRANSPORT_ADS,
2468                         "Issue LDAP search by DN",
2469                         "net ads dn\n"
2470                         "    Issue LDAP search by DN"
2471                 },
2472                 {
2473                         "sid",
2474                         net_ads_sid,
2475                         NET_TRANSPORT_ADS,
2476                         "Issue LDAP search by SID",
2477                         "net ads sid\n"
2478                         "    Issue LDAP search by SID"
2479                 },
2480                 {
2481                         "workgroup",
2482                         net_ads_workgroup,
2483                         NET_TRANSPORT_ADS,
2484                         "Display workgroup name",
2485                         "net ads workgroup\n"
2486                         "    Display the workgroup name"
2487                 },
2488                 {
2489                         "lookup",
2490                         net_ads_lookup,
2491                         NET_TRANSPORT_ADS,
2492                         "Perfom CLDAP query on DC",
2493                         "net ads lookup\n"
2494                         "    Find the ADS DC using CLDAP lookups"
2495                 },
2496                 {
2497                         "keytab",
2498                         net_ads_keytab,
2499                         NET_TRANSPORT_ADS,
2500                         "Manage local keytab file",
2501                         "net ads keytab\n"
2502                         "    Manage local keytab file"
2503                 },
2504                 {
2505                         "gpo",
2506                         net_ads_gpo,
2507                         NET_TRANSPORT_ADS,
2508                         "Manage group policy objects",
2509                         "net ads gpo\n"
2510                         "    Manage group policy objects"
2511                 },
2512                 {
2513                         "kerberos",
2514                         net_ads_kerberos,
2515                         NET_TRANSPORT_ADS,
2516                         "Manage kerberos keytab",
2517                         "net ads kerberos\n"
2518                         "    Manage kerberos keytab"
2519                 },
2520                 {NULL, NULL, 0, NULL, NULL}
2521         };
2522
2523         return net_run_function(c, argc, argv, "net ads", func);
2524 }
2525
2526 #else
2527
2528 static int net_ads_noads(void)
2529 {
2530         d_fprintf(stderr, "ADS support not compiled in\n");
2531         return -1;
2532 }
2533
2534 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2535 {
2536         return net_ads_noads();
2537 }
2538
2539 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2540 {
2541         return net_ads_noads();
2542 }
2543
2544 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2545 {
2546         return net_ads_noads();
2547 }
2548
2549 int net_ads_join(struct net_context *c, int argc, const char **argv)
2550 {
2551         return net_ads_noads();
2552 }
2553
2554 int net_ads_user(struct net_context *c, int argc, const char **argv)
2555 {
2556         return net_ads_noads();
2557 }
2558
2559 int net_ads_group(struct net_context *c, int argc, const char **argv)
2560 {
2561         return net_ads_noads();
2562 }
2563
2564 /* this one shouldn't display a message */
2565 int net_ads_check(struct net_context *c)
2566 {
2567         return -1;
2568 }
2569
2570 int net_ads_check_our_domain(struct net_context *c)
2571 {
2572         return -1;
2573 }
2574
2575 int net_ads(struct net_context *c, int argc, const char **argv)
2576 {
2577         return net_ads_noads();
2578 }
2579
2580 #endif  /* WITH_ADS */