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