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