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