88051ec4a1bfc55fa9c254dcfcd4e326e49de752
[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 (!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         d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1213                 r->out.dns_domain_name);
1214
1215 #if defined(WITH_DNS_UPDATES)
1216         {
1217                 /* We enter this block with user creds */
1218                 ADS_STRUCT *ads_dns = NULL;
1219
1220                 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1221                         /* kinit with the machine password */
1222
1223                         use_in_memory_ccache();
1224                         asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1225                         ads_dns->auth.password = secrets_fetch_machine_password(
1226                                 r->out.netbios_domain_name, NULL, NULL );
1227                         ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1228                         ads_kinit_password( ads_dns );
1229                 }
1230
1231                 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1232                         d_fprintf( stderr, "DNS update failed!\n" );
1233                 }
1234
1235                 /* exit from this block using machine creds */
1236                 ads_destroy(&ads_dns);
1237         }
1238 #endif
1239         TALLOC_FREE(r);
1240         TALLOC_FREE( ctx );
1241
1242         return 0;
1243
1244 fail:
1245         /* issue an overall failure message at the end. */
1246         d_printf("Failed to join domain: %s\n",
1247                 r && r->out.error_string ? r->out.error_string :
1248                 get_friendly_werror_msg(werr));
1249         TALLOC_FREE( ctx );
1250
1251         return -1;
1252 }
1253
1254 /*******************************************************************
1255  ********************************************************************/
1256
1257 static int net_ads_dns_usage(int argc, const char **argv)
1258 {
1259 #if defined(WITH_DNS_UPDATES)
1260         d_printf("net ads dns <command>\n");
1261         d_printf("Valid commands:\n");
1262         d_printf("   register         Issue a dynamic DNS update request for our hostname\n");
1263
1264         return 0;
1265 #else
1266         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1267         return -1;
1268 #endif
1269 }
1270
1271 /*******************************************************************
1272  ********************************************************************/
1273
1274 static int net_ads_dns_register(int argc, const char **argv)
1275 {
1276 #if defined(WITH_DNS_UPDATES)
1277         ADS_STRUCT *ads;
1278         ADS_STATUS status;
1279         TALLOC_CTX *ctx;
1280
1281 #ifdef DEVELOPER
1282         talloc_enable_leak_report();
1283 #endif
1284
1285         if (argc > 0) {
1286                 d_fprintf(stderr, "net ads dns register\n");
1287                 return -1;
1288         }
1289
1290         if (!(ctx = talloc_init("net_ads_dns"))) {
1291                 d_fprintf(stderr, "Could not initialise talloc context\n");
1292                 return -1;
1293         }
1294
1295         status = ads_startup(True, &ads);
1296         if ( !ADS_ERR_OK(status) ) {
1297                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1298                 TALLOC_FREE(ctx);
1299                 return -1;
1300         }
1301
1302         if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1303                 d_fprintf( stderr, "DNS update failed!\n" );
1304                 ads_destroy( &ads );
1305                 TALLOC_FREE( ctx );
1306                 return -1;
1307         }
1308
1309         d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1310
1311         ads_destroy(&ads);
1312         TALLOC_FREE( ctx );
1313
1314         return 0;
1315 #else
1316         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1317         return -1;
1318 #endif
1319 }
1320
1321 #if defined(WITH_DNS_UPDATES)
1322 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1323 #endif
1324
1325 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1326 {
1327 #if defined(WITH_DNS_UPDATES)
1328         DNS_ERROR err;
1329
1330 #ifdef DEVELOPER
1331         talloc_enable_leak_report();
1332 #endif
1333
1334         if (argc != 2) {
1335                 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1336                           "<name>\n");
1337                 return -1;
1338         }
1339
1340         err = do_gethostbyname(argv[0], argv[1]);
1341
1342         d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1343 #endif
1344         return 0;
1345 }
1346
1347 static int net_ads_dns(int argc, const char *argv[])
1348 {
1349         struct functable func[] = {
1350                 {"REGISTER", net_ads_dns_register},
1351                 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1352                 {NULL, NULL}
1353         };
1354
1355         return net_run_function(argc, argv, func, net_ads_dns_usage);
1356 }
1357
1358 /*******************************************************************
1359  ********************************************************************/
1360
1361 int net_ads_printer_usage(int argc, const char **argv)
1362 {
1363         d_printf(
1364 "\nnet ads printer search <printer>"
1365 "\n\tsearch for a printer in the directory\n"
1366 "\nnet ads printer info <printer> <server>"
1367 "\n\tlookup info in directory for printer on server"
1368 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1369 "\nnet ads printer publish <printername>"
1370 "\n\tpublish printer in directory"
1371 "\n\t(note: printer name is required)\n"
1372 "\nnet ads printer remove <printername>"
1373 "\n\tremove printer from directory"
1374 "\n\t(note: printer name is required)\n");
1375         return -1;
1376 }
1377
1378 /*******************************************************************
1379  ********************************************************************/
1380
1381 static int net_ads_printer_search(int argc, const char **argv)
1382 {
1383         ADS_STRUCT *ads;
1384         ADS_STATUS rc;
1385         LDAPMessage *res = NULL;
1386
1387         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1388                 return -1;
1389         }
1390
1391         rc = ads_find_printers(ads, &res);
1392
1393         if (!ADS_ERR_OK(rc)) {
1394                 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1395                 ads_msgfree(ads, res);
1396                 ads_destroy(&ads);
1397                 return -1;
1398         }
1399
1400         if (ads_count_replies(ads, res) == 0) {
1401                 d_fprintf(stderr, "No results found\n");
1402                 ads_msgfree(ads, res);
1403                 ads_destroy(&ads);
1404                 return -1;
1405         }
1406
1407         ads_dump(ads, res);
1408         ads_msgfree(ads, res);
1409         ads_destroy(&ads);
1410         return 0;
1411 }
1412
1413 static int net_ads_printer_info(int argc, const char **argv)
1414 {
1415         ADS_STRUCT *ads;
1416         ADS_STATUS rc;
1417         const char *servername, *printername;
1418         LDAPMessage *res = NULL;
1419
1420         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1421                 return -1;
1422         }
1423
1424         if (argc > 0) {
1425                 printername = argv[0];
1426         } else {
1427                 printername = "*";
1428         }
1429
1430         if (argc > 1) {
1431                 servername =  argv[1];
1432         } else {
1433                 servername = global_myname();
1434         }
1435
1436         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1437
1438         if (!ADS_ERR_OK(rc)) {
1439                 d_fprintf(stderr, "Server '%s' not found: %s\n",
1440                         servername, ads_errstr(rc));
1441                 ads_msgfree(ads, res);
1442                 ads_destroy(&ads);
1443                 return -1;
1444         }
1445
1446         if (ads_count_replies(ads, res) == 0) {
1447                 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1448                 ads_msgfree(ads, res);
1449                 ads_destroy(&ads);
1450                 return -1;
1451         }
1452
1453         ads_dump(ads, res);
1454         ads_msgfree(ads, res);
1455         ads_destroy(&ads);
1456
1457         return 0;
1458 }
1459
1460 static int net_ads_printer_publish(int argc, const char **argv)
1461 {
1462         ADS_STRUCT *ads;
1463         ADS_STATUS rc;
1464         const char *servername, *printername;
1465         struct cli_state *cli;
1466         struct rpc_pipe_client *pipe_hnd;
1467         struct sockaddr_storage server_ss;
1468         NTSTATUS nt_status;
1469         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1470         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1471         char *prt_dn, *srv_dn, **srv_cn;
1472         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1473         LDAPMessage *res = NULL;
1474
1475         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1476                 talloc_destroy(mem_ctx);
1477                 return -1;
1478         }
1479
1480         if (argc < 1) {
1481                 talloc_destroy(mem_ctx);
1482                 return net_ads_printer_usage(argc, argv);
1483         }
1484
1485         printername = argv[0];
1486
1487         if (argc == 2) {
1488                 servername = argv[1];
1489         } else {
1490                 servername = global_myname();
1491         }
1492
1493         /* Get printer data from SPOOLSS */
1494
1495         resolve_name(servername, &server_ss, 0x20);
1496
1497         nt_status = cli_full_connection(&cli, global_myname(), servername,
1498                                         &server_ss, 0,
1499                                         "IPC$", "IPC",
1500                                         opt_user_name, opt_workgroup,
1501                                         opt_password ? opt_password : "",
1502                                         CLI_FULL_CONNECTION_USE_KERBEROS,
1503                                         Undefined, NULL);
1504
1505         if (NT_STATUS_IS_ERR(nt_status)) {
1506                 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1507                          "for %s\n", servername, printername);
1508                 ads_destroy(&ads);
1509                 talloc_destroy(mem_ctx);
1510                 return -1;
1511         }
1512
1513         /* Publish on AD server */
1514
1515         ads_find_machine_acct(ads, &res, servername);
1516
1517         if (ads_count_replies(ads, res) == 0) {
1518                 d_fprintf(stderr, "Could not find machine account for server %s\n", 
1519                          servername);
1520                 ads_destroy(&ads);
1521                 talloc_destroy(mem_ctx);
1522                 return -1;
1523         }
1524
1525         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1526         srv_cn = ldap_explode_dn(srv_dn, 1);
1527
1528         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1529         printername_escaped = escape_rdn_val_string_alloc(printername);
1530         if (!srv_cn_escaped || !printername_escaped) {
1531                 SAFE_FREE(srv_cn_escaped);
1532                 SAFE_FREE(printername_escaped);
1533                 d_fprintf(stderr, "Internal error, out of memory!");
1534                 ads_destroy(&ads);
1535                 talloc_destroy(mem_ctx);
1536                 return -1;
1537         }
1538
1539         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1540
1541         SAFE_FREE(srv_cn_escaped);
1542         SAFE_FREE(printername_escaped);
1543
1544         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1545         if (!pipe_hnd) {
1546                 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1547                          servername);
1548                 SAFE_FREE(prt_dn);
1549                 ads_destroy(&ads);
1550                 talloc_destroy(mem_ctx);
1551                 return -1;
1552         }
1553
1554         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1555                                                               printername))) {
1556                 SAFE_FREE(prt_dn);
1557                 ads_destroy(&ads);
1558                 talloc_destroy(mem_ctx);
1559                 return -1;
1560         }
1561
1562         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1563         if (!ADS_ERR_OK(rc)) {
1564                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1565                 SAFE_FREE(prt_dn);
1566                 ads_destroy(&ads);
1567                 talloc_destroy(mem_ctx);
1568                 return -1;
1569         }
1570
1571         d_printf("published printer\n");
1572         SAFE_FREE(prt_dn);
1573         ads_destroy(&ads);
1574         talloc_destroy(mem_ctx);
1575
1576         return 0;
1577 }
1578
1579 static int net_ads_printer_remove(int argc, const char **argv)
1580 {
1581         ADS_STRUCT *ads;
1582         ADS_STATUS rc;
1583         const char *servername;
1584         char *prt_dn;
1585         LDAPMessage *res = NULL;
1586
1587         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1588                 return -1;
1589         }
1590
1591         if (argc < 1) {
1592                 return net_ads_printer_usage(argc, argv);
1593         }
1594
1595         if (argc > 1) {
1596                 servername = argv[1];
1597         } else {
1598                 servername = global_myname();
1599         }
1600
1601         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1602
1603         if (!ADS_ERR_OK(rc)) {
1604                 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1605                 ads_msgfree(ads, res);
1606                 ads_destroy(&ads);
1607                 return -1;
1608         }
1609
1610         if (ads_count_replies(ads, res) == 0) {
1611                 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1612                 ads_msgfree(ads, res);
1613                 ads_destroy(&ads);
1614                 return -1;
1615         }
1616
1617         prt_dn = ads_get_dn(ads, res);
1618         ads_msgfree(ads, res);
1619         rc = ads_del_dn(ads, prt_dn);
1620         ads_memfree(ads, prt_dn);
1621
1622         if (!ADS_ERR_OK(rc)) {
1623                 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1624                 ads_destroy(&ads);
1625                 return -1;
1626         }
1627
1628         ads_destroy(&ads);
1629         return 0;
1630 }
1631
1632 static int net_ads_printer(int argc, const char **argv)
1633 {
1634         struct functable func[] = {
1635                 {"SEARCH", net_ads_printer_search},
1636                 {"INFO", net_ads_printer_info},
1637                 {"PUBLISH", net_ads_printer_publish},
1638                 {"REMOVE", net_ads_printer_remove},
1639                 {NULL, NULL}
1640         };
1641
1642         return net_run_function(argc, argv, func, net_ads_printer_usage);
1643 }
1644
1645
1646 static int net_ads_password(int argc, const char **argv)
1647 {
1648         ADS_STRUCT *ads;
1649         const char *auth_principal = opt_user_name;
1650         const char *auth_password = opt_password;
1651         char *realm = NULL;
1652         char *new_password = NULL;
1653         char *c, *prompt;
1654         const char *user;
1655         ADS_STATUS ret;
1656
1657         if (opt_user_name == NULL || opt_password == NULL) {
1658                 d_fprintf(stderr, "You must supply an administrator username/password\n");
1659                 return -1;
1660         }
1661
1662         if (argc < 1) {
1663                 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1664                 return -1;
1665         }
1666
1667         user = argv[0];
1668         if (!strchr_m(user, '@')) {
1669                 asprintf(&c, "%s@%s", argv[0], lp_realm());
1670                 user = c;
1671         }
1672
1673         use_in_memory_ccache();
1674         c = strchr_m(auth_principal, '@');
1675         if (c) {
1676                 realm = ++c;
1677         } else {
1678                 realm = lp_realm();
1679         }
1680
1681         /* use the realm so we can eventually change passwords for users
1682         in realms other than default */
1683         if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1684                 return -1;
1685         }
1686
1687         /* we don't actually need a full connect, but it's the easy way to
1688                 fill in the KDC's addresss */
1689         ads_connect(ads);
1690
1691         if (!ads->config.realm) {
1692                 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1693                 return -1;
1694         }
1695
1696         if (argv[1]) {
1697                 new_password = (char *)argv[1];
1698         } else {
1699                 asprintf(&prompt, "Enter new password for %s:", user);
1700                 new_password = getpass(prompt);
1701                 free(prompt);
1702         }
1703
1704         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1705                                 auth_password, user, new_password, ads->auth.time_offset);
1706         if (!ADS_ERR_OK(ret)) {
1707                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1708                 ads_destroy(&ads);
1709                 return -1;
1710         }
1711
1712         d_printf("Password change for %s completed.\n", user);
1713         ads_destroy(&ads);
1714
1715         return 0;
1716 }
1717
1718 int net_ads_changetrustpw(int argc, const char **argv)
1719 {
1720         ADS_STRUCT *ads;
1721         char *host_principal;
1722         fstring my_name;
1723         ADS_STATUS ret;
1724
1725         if (!secrets_init()) {
1726                 DEBUG(1,("Failed to initialise secrets database\n"));
1727                 return -1;
1728         }
1729
1730         net_use_krb_machine_account();
1731
1732         use_in_memory_ccache();
1733
1734         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1735                 return -1;
1736         }
1737
1738         fstrcpy(my_name, global_myname());
1739         strlower_m(my_name);
1740         asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1741         d_printf("Changing password for principal: %s\n", host_principal);
1742
1743         ret = ads_change_trust_account_password(ads, host_principal);
1744
1745         if (!ADS_ERR_OK(ret)) {
1746                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1747                 ads_destroy(&ads);
1748                 SAFE_FREE(host_principal);
1749                 return -1;
1750         }
1751
1752         d_printf("Password change for principal %s succeeded.\n", host_principal);
1753
1754         if (lp_use_kerberos_keytab()) {
1755                 d_printf("Attempting to update system keytab with new password.\n");
1756                 if (ads_keytab_create_default(ads)) {
1757                         d_printf("Failed to update system keytab.\n");
1758                 }
1759         }
1760
1761         ads_destroy(&ads);
1762         SAFE_FREE(host_principal);
1763
1764         return 0;
1765 }
1766
1767 /*
1768   help for net ads search
1769 */
1770 static int net_ads_search_usage(int argc, const char **argv)
1771 {
1772         d_printf(
1773                 "\nnet ads search <expression> <attributes...>\n"\
1774                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1775                 "The expression is a standard LDAP search expression, and the\n"\
1776                 "attributes are a list of LDAP fields to show in the results\n\n"\
1777                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1778                 );
1779         net_common_flags_usage(argc, argv);
1780         return -1;
1781 }
1782
1783
1784 /*
1785   general ADS search function. Useful in diagnosing problems in ADS
1786 */
1787 static int net_ads_search(int argc, const char **argv)
1788 {
1789         ADS_STRUCT *ads;
1790         ADS_STATUS rc;
1791         const char *ldap_exp;
1792         const char **attrs;
1793         LDAPMessage *res = NULL;
1794
1795         if (argc < 1) {
1796                 return net_ads_search_usage(argc, argv);
1797         }
1798
1799         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1800                 return -1;
1801         }
1802
1803         ldap_exp = argv[0];
1804         attrs = (argv + 1);
1805
1806         rc = ads_do_search_all(ads, ads->config.bind_path,
1807                                LDAP_SCOPE_SUBTREE,
1808                                ldap_exp, attrs, &res);
1809         if (!ADS_ERR_OK(rc)) {
1810                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1811                 ads_destroy(&ads);
1812                 return -1;
1813         }
1814
1815         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1816
1817         /* dump the results */
1818         ads_dump(ads, res);
1819
1820         ads_msgfree(ads, res);
1821         ads_destroy(&ads);
1822
1823         return 0;
1824 }
1825
1826
1827 /*
1828   help for net ads search
1829 */
1830 static int net_ads_dn_usage(int argc, const char **argv)
1831 {
1832         d_printf(
1833                 "\nnet ads dn <dn> <attributes...>\n"\
1834                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1835                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1836                 "to show in the results\n\n"\
1837                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1838                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1839                 );
1840         net_common_flags_usage(argc, argv);
1841         return -1;
1842 }
1843
1844
1845 /*
1846   general ADS search function. Useful in diagnosing problems in ADS
1847 */
1848 static int net_ads_dn(int argc, const char **argv)
1849 {
1850         ADS_STRUCT *ads;
1851         ADS_STATUS rc;
1852         const char *dn;
1853         const char **attrs;
1854         LDAPMessage *res = NULL;
1855
1856         if (argc < 1) {
1857                 return net_ads_dn_usage(argc, argv);
1858         }
1859
1860         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1861                 return -1;
1862         }
1863
1864         dn = argv[0];
1865         attrs = (argv + 1);
1866
1867         rc = ads_do_search_all(ads, dn,
1868                                LDAP_SCOPE_BASE,
1869                                "(objectclass=*)", attrs, &res);
1870         if (!ADS_ERR_OK(rc)) {
1871                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1872                 ads_destroy(&ads);
1873                 return -1;
1874         }
1875
1876         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1877
1878         /* dump the results */
1879         ads_dump(ads, res);
1880
1881         ads_msgfree(ads, res);
1882         ads_destroy(&ads);
1883
1884         return 0;
1885 }
1886
1887 /*
1888   help for net ads sid search
1889 */
1890 static int net_ads_sid_usage(int argc, const char **argv)
1891 {
1892         d_printf(
1893                 "\nnet ads sid <sid> <attributes...>\n"\
1894                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1895                 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1896                 "to show in the results\n\n"\
1897                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1898                 );
1899         net_common_flags_usage(argc, argv);
1900         return -1;
1901 }
1902
1903
1904 /*
1905   general ADS search function. Useful in diagnosing problems in ADS
1906 */
1907 static int net_ads_sid(int argc, const char **argv)
1908 {
1909         ADS_STRUCT *ads;
1910         ADS_STATUS rc;
1911         const char *sid_string;
1912         const char **attrs;
1913         LDAPMessage *res = NULL;
1914         DOM_SID sid;
1915
1916         if (argc < 1) {
1917                 return net_ads_sid_usage(argc, argv);
1918         }
1919
1920         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1921                 return -1;
1922         }
1923
1924         sid_string = argv[0];
1925         attrs = (argv + 1);
1926
1927         if (!string_to_sid(&sid, sid_string)) {
1928                 d_fprintf(stderr, "could not convert sid\n");
1929                 ads_destroy(&ads);
1930                 return -1;
1931         }
1932
1933         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
1934         if (!ADS_ERR_OK(rc)) {
1935                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1936                 ads_destroy(&ads);
1937                 return -1;
1938         }
1939
1940         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1941
1942         /* dump the results */
1943         ads_dump(ads, res);
1944
1945         ads_msgfree(ads, res);
1946         ads_destroy(&ads);
1947
1948         return 0;
1949 }
1950
1951
1952 static int net_ads_keytab_usage(int argc, const char **argv)
1953 {
1954         d_printf(
1955                 "net ads keytab <COMMAND>\n"\
1956 "<COMMAND> can be either:\n"\
1957 "  ADD       Adds new service principal\n"\
1958 "  CREATE    Creates a fresh keytab\n"\
1959 "  FLUSH     Flushes out all keytab entries\n"\
1960 "  HELP      Prints this help message\n"\
1961 "  LIST      List the keytab\n"\
1962 "The ADD and LIST command will take arguments, the other commands\n"\
1963 "will not take any arguments.   The arguments given to ADD\n"\
1964 "should be a list of principals to add.  For example, \n"\
1965 "   net ads keytab add srv1 srv2\n"\
1966 "will add principals for the services srv1 and srv2 to the\n"\
1967 "system's keytab.\n"\
1968 "The LIST command takes a keytabname.\n"\
1969 "\n"
1970                 );
1971         return -1;
1972 }
1973
1974 static int net_ads_keytab_flush(int argc, const char **argv)
1975 {
1976         int ret;
1977         ADS_STRUCT *ads;
1978
1979         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1980                 return -1;
1981         }
1982         ret = ads_keytab_flush(ads);
1983         ads_destroy(&ads);
1984         return ret;
1985 }
1986
1987 static int net_ads_keytab_add(int argc, const char **argv)
1988 {
1989         int i;
1990         int ret = 0;
1991         ADS_STRUCT *ads;
1992
1993         d_printf("Processing principals to add...\n");
1994         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1995                 return -1;
1996         }
1997         for (i = 0; i < argc; i++) {
1998                 ret |= ads_keytab_add_entry(ads, argv[i]);
1999         }
2000         ads_destroy(&ads);
2001         return ret;
2002 }
2003
2004 static int net_ads_keytab_create(int argc, const char **argv)
2005 {
2006         ADS_STRUCT *ads;
2007         int ret;
2008
2009         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2010                 return -1;
2011         }
2012         ret = ads_keytab_create_default(ads);
2013         ads_destroy(&ads);
2014         return ret;
2015 }
2016
2017 static int net_ads_keytab_list(int argc, const char **argv)
2018 {
2019         const char *keytab = NULL;
2020
2021         if (argc >= 1) {
2022                 keytab = argv[0];
2023         }
2024
2025         return ads_keytab_list(keytab);
2026 }
2027
2028
2029 int net_ads_keytab(int argc, const char **argv)
2030 {
2031         struct functable func[] = {
2032                 {"ADD", net_ads_keytab_add},
2033                 {"CREATE", net_ads_keytab_create},
2034                 {"FLUSH", net_ads_keytab_flush},
2035                 {"HELP", net_ads_keytab_usage},
2036                 {"LIST", net_ads_keytab_list},
2037                 {NULL, NULL}
2038         };
2039
2040         if (!lp_use_kerberos_keytab()) {
2041                 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2042 use keytab functions.\n");
2043         }
2044
2045         return net_run_function(argc, argv, func, net_ads_keytab_usage);
2046 }
2047
2048 static int net_ads_kerberos_usage(int argc, const char **argv)
2049 {
2050         d_printf(
2051                 "net ads kerberos <COMMAND>\n"\
2052                 "<COMMAND> can be either:\n"\
2053                 "  RENEW     Renew TGT from existing credential cache\n"\
2054                 "  PAC       Dumps the Kerberos PAC\n"\
2055                 "  KINIT     Retrieve Ticket Granting Ticket (TGT)\n"\
2056                 "\n"
2057         );
2058
2059         return -1;
2060 }
2061
2062 static int net_ads_kerberos_renew(int argc, const char **argv)
2063 {
2064         int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2065         if (ret) {
2066                 d_printf("failed to renew kerberos ticket: %s\n",
2067                         error_message(ret));
2068         }
2069         return ret;
2070 }
2071
2072 static int net_ads_kerberos_pac(int argc, const char **argv)
2073 {
2074         struct PAC_DATA *pac = NULL;
2075         struct PAC_LOGON_INFO *info = NULL;
2076         TALLOC_CTX *mem_ctx = NULL;
2077         NTSTATUS status;
2078         int ret = -1;
2079
2080         mem_ctx = talloc_init("net_ads_kerberos_pac");
2081         if (!mem_ctx) {
2082                 goto out;
2083         }
2084
2085         opt_password = net_prompt_pass(opt_user_name);
2086
2087         status = kerberos_return_pac(mem_ctx,
2088                                      opt_user_name,
2089                                      opt_password,
2090                                      0,
2091                                      NULL,
2092                                      NULL,
2093                                      NULL,
2094                                      True,
2095                                      True,
2096                                      2592000, /* one month */
2097                                      &pac);
2098         if (!NT_STATUS_IS_OK(status)) {
2099                 d_printf("failed to query kerberos PAC: %s\n",
2100                         nt_errstr(status));
2101                 goto out;
2102         }
2103
2104         info = get_logon_info_from_pac(pac);
2105         if (info) {
2106                 const char *s;
2107                 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2108                 d_printf("The Pac: %s\n", s);
2109         }
2110
2111         ret = 0;
2112  out:
2113         TALLOC_FREE(mem_ctx);
2114         return ret;
2115 }
2116
2117 static int net_ads_kerberos_kinit(int argc, const char **argv)
2118 {
2119         TALLOC_CTX *mem_ctx = NULL;
2120         int ret = -1;
2121         NTSTATUS status;
2122
2123         mem_ctx = talloc_init("net_ads_kerberos_kinit");
2124         if (!mem_ctx) {
2125                 goto out;
2126         }
2127
2128         opt_password = net_prompt_pass(opt_user_name);
2129
2130         ret = kerberos_kinit_password_ext(opt_user_name,
2131                                           opt_password,
2132                                           0,
2133                                           NULL,
2134                                           NULL,
2135                                           NULL,
2136                                           True,
2137                                           True,
2138                                           2592000, /* one month */
2139                                           &status);
2140         if (ret) {
2141                 d_printf("failed to kinit password: %s\n",
2142                         nt_errstr(status));
2143         }
2144  out:
2145         return ret;
2146 }
2147
2148 int net_ads_kerberos(int argc, const char **argv)
2149 {
2150         struct functable func[] = {
2151                 {"KINIT", net_ads_kerberos_kinit},
2152                 {"RENEW", net_ads_kerberos_renew},
2153                 {"PAC", net_ads_kerberos_pac},
2154                 {"HELP", net_ads_kerberos_usage},
2155                 {NULL, NULL}
2156         };
2157
2158         return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2159 }
2160
2161
2162 int net_ads_help(int argc, const char **argv)
2163 {
2164         struct functable func[] = {
2165                 {"USER", net_ads_user_usage},
2166                 {"GROUP", net_ads_group_usage},
2167                 {"PRINTER", net_ads_printer_usage},
2168                 {"SEARCH", net_ads_search_usage},
2169                 {"INFO", net_ads_info},
2170                 {"JOIN", net_ads_join_usage},
2171                 {"DNS", net_ads_dns_usage},
2172                 {"LEAVE", net_ads_leave},
2173                 {"STATUS", net_ads_status},
2174                 {"PASSWORD", net_ads_password},
2175                 {"CHANGETRUSTPW", net_ads_changetrustpw},
2176                 {NULL, NULL}
2177         };
2178
2179         return net_run_function(argc, argv, func, net_ads_usage);
2180 }
2181
2182 int net_ads(int argc, const char **argv)
2183 {
2184         struct functable func[] = {
2185                 {"INFO", net_ads_info},
2186                 {"JOIN", net_ads_join},
2187                 {"TESTJOIN", net_ads_testjoin},
2188                 {"LEAVE", net_ads_leave},
2189                 {"STATUS", net_ads_status},
2190                 {"USER", net_ads_user},
2191                 {"GROUP", net_ads_group},
2192                 {"DNS", net_ads_dns},
2193                 {"PASSWORD", net_ads_password},
2194                 {"CHANGETRUSTPW", net_ads_changetrustpw},
2195                 {"PRINTER", net_ads_printer},
2196                 {"SEARCH", net_ads_search},
2197                 {"DN", net_ads_dn},
2198                 {"SID", net_ads_sid},
2199                 {"WORKGROUP", net_ads_workgroup},
2200                 {"LOOKUP", net_ads_lookup},
2201                 {"KEYTAB", net_ads_keytab},
2202                 {"GPO", net_ads_gpo},
2203                 {"KERBEROS", net_ads_kerberos},
2204                 {"HELP", net_ads_help},
2205                 {NULL, NULL}
2206         };
2207
2208         return net_run_function(argc, argv, func, net_ads_usage);
2209 }
2210
2211 #else
2212
2213 static int net_ads_noads(void)
2214 {
2215         d_fprintf(stderr, "ADS support not compiled in\n");
2216         return -1;
2217 }
2218
2219 int net_ads_keytab(int argc, const char **argv)
2220 {
2221         return net_ads_noads();
2222 }
2223
2224 int net_ads_kerberos(int argc, const char **argv)
2225 {
2226         return net_ads_noads();
2227 }
2228
2229 int net_ads_usage(int argc, const char **argv)
2230 {
2231         return net_ads_noads();
2232 }
2233
2234 int net_ads_help(int argc, const char **argv)
2235 {
2236         return net_ads_noads();
2237 }
2238
2239 int net_ads_changetrustpw(int argc, const char **argv)
2240 {
2241         return net_ads_noads();
2242 }
2243
2244 int net_ads_join(int argc, const char **argv)
2245 {
2246         return net_ads_noads();
2247 }
2248
2249 int net_ads_user(int argc, const char **argv)
2250 {
2251         return net_ads_noads();
2252 }
2253
2254 int net_ads_group(int argc, const char **argv)
2255 {
2256         return net_ads_noads();
2257 }
2258
2259 /* this one shouldn't display a message */
2260 int net_ads_check(void)
2261 {
2262         return -1;
2263 }
2264
2265 int net_ads_check_our_domain(void)
2266 {
2267         return -1;
2268 }
2269
2270 int net_ads(int argc, const char **argv)
2271 {
2272         return net_ads_usage(argc, argv);
2273 }
2274
2275 #endif  /* WITH_ADS */