net: use WERROR for check_ads_config().
[nivanova/samba-autobuild/.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             = true;
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 WERROR 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 WERR_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 WERR_INVALID_COMPUTER_NAME;
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 WERR_INVALID_PARAM;
939         }
940
941         return WERR_OK;
942 }
943
944 /*******************************************************************
945  Send a DNS update request
946 *******************************************************************/
947
948 #if defined(WITH_DNS_UPDATES)
949 #include "dns.h"
950 DNS_ERROR DoDNSUpdate(char *pszServerName,
951                       const char *pszDomainName, const char *pszHostName,
952                       const struct sockaddr_storage *sslist,
953                       size_t num_addrs );
954
955 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
956                                         const char *machine_name,
957                                         const struct sockaddr_storage *addrs,
958                                         int num_addrs)
959 {
960         struct dns_rr_ns *nameservers = NULL;
961         int ns_count = 0;
962         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
963         DNS_ERROR dns_err;
964         fstring dns_server;
965         const char *dnsdomain = NULL;
966         char *root_domain = NULL;
967
968         if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
969                 d_printf("No DNS domain configured for %s. "
970                          "Unable to perform DNS Update.\n", machine_name);
971                 status = NT_STATUS_INVALID_PARAMETER;
972                 goto done;
973         }
974         dnsdomain++;
975
976         status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
977         if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
978                 /* Child domains often do not have NS records.  Look
979                    for the NS record for the forest root domain
980                    (rootDomainNamingContext in therootDSE) */
981
982                 const char *rootname_attrs[] =  { "rootDomainNamingContext", NULL };
983                 LDAPMessage *msg = NULL;
984                 char *root_dn;
985                 ADS_STATUS ads_status;
986
987                 if ( !ads->ldap.ld ) {
988                         ads_status = ads_connect( ads );
989                         if ( !ADS_ERR_OK(ads_status) ) {
990                                 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
991                                 goto done;
992                         }
993                 }
994
995                 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
996                                        "(objectclass=*)", rootname_attrs, &msg);
997                 if (!ADS_ERR_OK(ads_status)) {
998                         goto done;
999                 }
1000
1001                 root_dn = ads_pull_string(ads, ctx, msg,  "rootDomainNamingContext");
1002                 if ( !root_dn ) {
1003                         ads_msgfree( ads, msg );
1004                         goto done;
1005                 }
1006
1007                 root_domain = ads_build_domain( root_dn );
1008
1009                 /* cleanup */
1010                 ads_msgfree( ads, msg );
1011
1012                 /* try again for NS servers */
1013
1014                 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1015
1016                 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1017                         DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1018                          "realm\n", ads->config.realm));
1019                         goto done;
1020                 }
1021
1022                 dnsdomain = root_domain;
1023
1024         }
1025
1026         /* Now perform the dns update - we'll try non-secure and if we fail,
1027            we'll follow it up with a secure update */
1028
1029         fstrcpy( dns_server, nameservers[0].hostname );
1030
1031         dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1032         if (!ERR_DNS_IS_OK(dns_err)) {
1033                 status = NT_STATUS_UNSUCCESSFUL;
1034         }
1035
1036 done:
1037
1038         SAFE_FREE( root_domain );
1039
1040         return status;
1041 }
1042
1043 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1044 {
1045         int num_addrs;
1046         struct sockaddr_storage *iplist = NULL;
1047         fstring machine_name;
1048         NTSTATUS status;
1049
1050         name_to_fqdn( machine_name, global_myname() );
1051         strlower_m( machine_name );
1052
1053         /* Get our ip address (not the 127.0.0.x address but a real ip
1054          * address) */
1055
1056         num_addrs = get_my_ip_address( &iplist );
1057         if ( num_addrs <= 0 ) {
1058                 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1059                          "addresses!\n"));
1060                 return NT_STATUS_INVALID_PARAMETER;
1061         }
1062
1063         status = net_update_dns_internal(mem_ctx, ads, machine_name,
1064                                          iplist, num_addrs);
1065         SAFE_FREE( iplist );
1066         return status;
1067 }
1068 #endif
1069
1070
1071 /*******************************************************************
1072  ********************************************************************/
1073
1074 static int net_ads_join_usage(int argc, const char **argv)
1075 {
1076         d_printf("net ads join [options]\n");
1077         d_printf("Valid options:\n");
1078         d_printf("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n");
1079         d_printf("                      The deault UPN is in the form host/netbiosname@REALM.\n");
1080         d_printf("   createcomputer=OU  Precreate the computer account in a specific OU.\n");
1081         d_printf("                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1082         d_printf("                      E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1083         d_printf("                      NB: A backslash '\\' is used as escape at multiple levels and may\n");
1084         d_printf("                          need to be doubled or even quadrupled.  It is not used as a separator.\n");
1085         d_printf("   osName=string      Set the operatingSystem attribute during the join.\n");
1086         d_printf("   osVer=string       Set the operatingSystemVersion attribute during the join.\n");
1087         d_printf("                      NB: osName and osVer must be specified together for either to take effect.\n");
1088         d_printf("                          Also, the operatingSystemService attribute is also set when along with\n");
1089         d_printf("                          the two other attributes.\n");
1090
1091         return -1;
1092 }
1093
1094 /*******************************************************************
1095  ********************************************************************/
1096
1097 int net_ads_join(int argc, const char **argv)
1098 {
1099         TALLOC_CTX *ctx = NULL;
1100         struct libnet_JoinCtx *r = NULL;
1101         const char *domain = lp_realm();
1102         WERROR werr = WERR_SETUP_NOT_JOINED;
1103         bool createupn = False;
1104         const char *machineupn = NULL;
1105         const char *create_in_ou = NULL;
1106         int i;
1107         const char *os_name = NULL;
1108         const char *os_version = NULL;
1109
1110         werr = check_ads_config();
1111         if (!W_ERROR_IS_OK(werr)) {
1112                 d_fprintf(stderr, "Invalid configuration.  Exiting....\n");
1113                 goto fail;
1114         }
1115
1116         if (!(ctx = talloc_init("net_ads_join"))) {
1117                 d_fprintf(stderr, "Could not initialise talloc context.\n");
1118                 werr = WERR_NOMEM;
1119                 goto fail;
1120         }
1121
1122         use_in_memory_ccache();
1123
1124         werr = libnet_init_JoinCtx(ctx, &r);
1125         if (!W_ERROR_IS_OK(werr)) {
1126                 goto fail;
1127         }
1128
1129         /* process additional command line args */
1130
1131         for ( i=0; i<argc; i++ ) {
1132                 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1133                         createupn = True;
1134                         machineupn = get_string_param(argv[i]);
1135                 }
1136                 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1137                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1138                                 d_fprintf(stderr, "Please supply a valid OU path.\n");
1139                                 werr = WERR_INVALID_PARAM;
1140                                 goto fail;
1141                         }
1142                 }
1143                 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1144                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1145                                 d_fprintf(stderr, "Please supply a operating system name.\n");
1146                                 werr = WERR_INVALID_PARAM;
1147                                 goto fail;
1148                         }
1149                 }
1150                 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1151                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1152                                 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1153                                 werr = WERR_INVALID_PARAM;
1154                                 goto fail;
1155                         }
1156                 }
1157                 else {
1158                         domain = argv[i];
1159                 }
1160         }
1161
1162         /* Do the domain join here */
1163
1164         r->in.domain_name       = domain;
1165         r->in.create_upn        = createupn;
1166         r->in.upn               = machineupn;
1167         r->in.account_ou        = create_in_ou;
1168         r->in.os_name           = os_name;
1169         r->in.os_version        = os_version;
1170         r->in.dc_name           = opt_host;
1171         r->in.admin_account     = opt_user_name;
1172         r->in.admin_password    = net_prompt_pass(opt_user_name);
1173         r->in.debug             = true;
1174         r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1175                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1176                                   WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1177
1178         werr = libnet_Join(ctx, r);
1179         if (!W_ERROR_IS_OK(werr)) {
1180                 goto fail;
1181         }
1182
1183         /* Check the short name of the domain */
1184
1185         if (!strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1186                 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1187                 d_printf("domain name obtained from the server.\n");
1188                 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1189                 d_printf("You should set \"workgroup = %s\" in %s.\n",
1190                          r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1191         }
1192
1193         d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1194
1195         d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1196                 r->out.dns_domain_name);
1197
1198 #if defined(WITH_DNS_UPDATES)
1199         {
1200                 /* We enter this block with user creds */
1201                 ADS_STRUCT *ads_dns = NULL;
1202
1203                 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1204                         /* kinit with the machine password */
1205
1206                         use_in_memory_ccache();
1207                         asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1208                         ads_dns->auth.password = secrets_fetch_machine_password(
1209                                 lp_workgroup(), NULL, NULL );
1210                         ads_dns->auth.realm = SMB_STRDUP( lp_realm() );
1211                         ads_kinit_password( ads_dns );
1212                 }
1213
1214                 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1215                         d_fprintf( stderr, "DNS update failed!\n" );
1216                 }
1217
1218                 /* exit from this block using machine creds */
1219                 ads_destroy(&ads_dns);
1220         }
1221 #endif
1222         TALLOC_FREE(r);
1223         TALLOC_FREE( ctx );
1224
1225         return 0;
1226
1227 fail:
1228         /* issue an overall failure message at the end. */
1229         d_printf("Failed to join domain: %s\n",
1230                 r && r->out.error_string ? r->out.error_string :
1231                 get_friendly_werror_msg(werr));
1232         TALLOC_FREE( ctx );
1233
1234         return -1;
1235 }
1236
1237 /*******************************************************************
1238  ********************************************************************/
1239
1240 static int net_ads_dns_usage(int argc, const char **argv)
1241 {
1242 #if defined(WITH_DNS_UPDATES)
1243         d_printf("net ads dns <command>\n");
1244         d_printf("Valid commands:\n");
1245         d_printf("   register         Issue a dynamic DNS update request for our hostname\n");
1246
1247         return 0;
1248 #else
1249         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1250         return -1;
1251 #endif
1252 }
1253
1254 /*******************************************************************
1255  ********************************************************************/
1256
1257 static int net_ads_dns_register(int argc, const char **argv)
1258 {
1259 #if defined(WITH_DNS_UPDATES)
1260         ADS_STRUCT *ads;
1261         ADS_STATUS status;
1262         TALLOC_CTX *ctx;
1263
1264 #ifdef DEVELOPER
1265         talloc_enable_leak_report();
1266 #endif
1267
1268         if (argc > 0) {
1269                 d_fprintf(stderr, "net ads dns register\n");
1270                 return -1;
1271         }
1272
1273         if (!(ctx = talloc_init("net_ads_dns"))) {
1274                 d_fprintf(stderr, "Could not initialise talloc context\n");
1275                 return -1;
1276         }
1277
1278         status = ads_startup(True, &ads);
1279         if ( !ADS_ERR_OK(status) ) {
1280                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1281                 TALLOC_FREE(ctx);
1282                 return -1;
1283         }
1284
1285         if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1286                 d_fprintf( stderr, "DNS update failed!\n" );
1287                 ads_destroy( &ads );
1288                 TALLOC_FREE( ctx );
1289                 return -1;
1290         }
1291
1292         d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1293
1294         ads_destroy(&ads);
1295         TALLOC_FREE( ctx );
1296
1297         return 0;
1298 #else
1299         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1300         return -1;
1301 #endif
1302 }
1303
1304 #if defined(WITH_DNS_UPDATES)
1305 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1306 #endif
1307
1308 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1309 {
1310 #if defined(WITH_DNS_UPDATES)
1311         DNS_ERROR err;
1312
1313 #ifdef DEVELOPER
1314         talloc_enable_leak_report();
1315 #endif
1316
1317         if (argc != 2) {
1318                 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1319                           "<name>\n");
1320                 return -1;
1321         }
1322
1323         err = do_gethostbyname(argv[0], argv[1]);
1324
1325         d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1326 #endif
1327         return 0;
1328 }
1329
1330 static int net_ads_dns(int argc, const char *argv[])
1331 {
1332         struct functable func[] = {
1333                 {"REGISTER", net_ads_dns_register},
1334                 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1335                 {NULL, NULL}
1336         };
1337
1338         return net_run_function(argc, argv, func, net_ads_dns_usage);
1339 }
1340
1341 /*******************************************************************
1342  ********************************************************************/
1343
1344 int net_ads_printer_usage(int argc, const char **argv)
1345 {
1346         d_printf(
1347 "\nnet ads printer search <printer>"
1348 "\n\tsearch for a printer in the directory\n"
1349 "\nnet ads printer info <printer> <server>"
1350 "\n\tlookup info in directory for printer on server"
1351 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1352 "\nnet ads printer publish <printername>"
1353 "\n\tpublish printer in directory"
1354 "\n\t(note: printer name is required)\n"
1355 "\nnet ads printer remove <printername>"
1356 "\n\tremove printer from directory"
1357 "\n\t(note: printer name is required)\n");
1358         return -1;
1359 }
1360
1361 /*******************************************************************
1362  ********************************************************************/
1363
1364 static int net_ads_printer_search(int argc, const char **argv)
1365 {
1366         ADS_STRUCT *ads;
1367         ADS_STATUS rc;
1368         LDAPMessage *res = NULL;
1369
1370         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1371                 return -1;
1372         }
1373
1374         rc = ads_find_printers(ads, &res);
1375
1376         if (!ADS_ERR_OK(rc)) {
1377                 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1378                 ads_msgfree(ads, res);
1379                 ads_destroy(&ads);
1380                 return -1;
1381         }
1382
1383         if (ads_count_replies(ads, res) == 0) {
1384                 d_fprintf(stderr, "No results found\n");
1385                 ads_msgfree(ads, res);
1386                 ads_destroy(&ads);
1387                 return -1;
1388         }
1389
1390         ads_dump(ads, res);
1391         ads_msgfree(ads, res);
1392         ads_destroy(&ads);
1393         return 0;
1394 }
1395
1396 static int net_ads_printer_info(int argc, const char **argv)
1397 {
1398         ADS_STRUCT *ads;
1399         ADS_STATUS rc;
1400         const char *servername, *printername;
1401         LDAPMessage *res = NULL;
1402
1403         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1404                 return -1;
1405         }
1406
1407         if (argc > 0) {
1408                 printername = argv[0];
1409         } else {
1410                 printername = "*";
1411         }
1412
1413         if (argc > 1) {
1414                 servername =  argv[1];
1415         } else {
1416                 servername = global_myname();
1417         }
1418
1419         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1420
1421         if (!ADS_ERR_OK(rc)) {
1422                 d_fprintf(stderr, "Server '%s' not found: %s\n",
1423                         servername, ads_errstr(rc));
1424                 ads_msgfree(ads, res);
1425                 ads_destroy(&ads);
1426                 return -1;
1427         }
1428
1429         if (ads_count_replies(ads, res) == 0) {
1430                 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1431                 ads_msgfree(ads, res);
1432                 ads_destroy(&ads);
1433                 return -1;
1434         }
1435
1436         ads_dump(ads, res);
1437         ads_msgfree(ads, res);
1438         ads_destroy(&ads);
1439
1440         return 0;
1441 }
1442
1443 static int net_ads_printer_publish(int argc, const char **argv)
1444 {
1445         ADS_STRUCT *ads;
1446         ADS_STATUS rc;
1447         const char *servername, *printername;
1448         struct cli_state *cli;
1449         struct rpc_pipe_client *pipe_hnd;
1450         struct sockaddr_storage server_ss;
1451         NTSTATUS nt_status;
1452         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1453         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1454         char *prt_dn, *srv_dn, **srv_cn;
1455         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1456         LDAPMessage *res = NULL;
1457
1458         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1459                 talloc_destroy(mem_ctx);
1460                 return -1;
1461         }
1462
1463         if (argc < 1) {
1464                 talloc_destroy(mem_ctx);
1465                 return net_ads_printer_usage(argc, argv);
1466         }
1467
1468         printername = argv[0];
1469
1470         if (argc == 2) {
1471                 servername = argv[1];
1472         } else {
1473                 servername = global_myname();
1474         }
1475
1476         /* Get printer data from SPOOLSS */
1477
1478         resolve_name(servername, &server_ss, 0x20);
1479
1480         nt_status = cli_full_connection(&cli, global_myname(), servername,
1481                                         &server_ss, 0,
1482                                         "IPC$", "IPC",
1483                                         opt_user_name, opt_workgroup,
1484                                         opt_password ? opt_password : "",
1485                                         CLI_FULL_CONNECTION_USE_KERBEROS,
1486                                         Undefined, NULL);
1487
1488         if (NT_STATUS_IS_ERR(nt_status)) {
1489                 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1490                          "for %s\n", servername, printername);
1491                 ads_destroy(&ads);
1492                 talloc_destroy(mem_ctx);
1493                 return -1;
1494         }
1495
1496         /* Publish on AD server */
1497
1498         ads_find_machine_acct(ads, &res, servername);
1499
1500         if (ads_count_replies(ads, res) == 0) {
1501                 d_fprintf(stderr, "Could not find machine account for server %s\n", 
1502                          servername);
1503                 ads_destroy(&ads);
1504                 talloc_destroy(mem_ctx);
1505                 return -1;
1506         }
1507
1508         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1509         srv_cn = ldap_explode_dn(srv_dn, 1);
1510
1511         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1512         printername_escaped = escape_rdn_val_string_alloc(printername);
1513         if (!srv_cn_escaped || !printername_escaped) {
1514                 SAFE_FREE(srv_cn_escaped);
1515                 SAFE_FREE(printername_escaped);
1516                 d_fprintf(stderr, "Internal error, out of memory!");
1517                 ads_destroy(&ads);
1518                 talloc_destroy(mem_ctx);
1519                 return -1;
1520         }
1521
1522         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1523
1524         SAFE_FREE(srv_cn_escaped);
1525         SAFE_FREE(printername_escaped);
1526
1527         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1528         if (!pipe_hnd) {
1529                 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1530                          servername);
1531                 SAFE_FREE(prt_dn);
1532                 ads_destroy(&ads);
1533                 talloc_destroy(mem_ctx);
1534                 return -1;
1535         }
1536
1537         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1538                                                               printername))) {
1539                 SAFE_FREE(prt_dn);
1540                 ads_destroy(&ads);
1541                 talloc_destroy(mem_ctx);
1542                 return -1;
1543         }
1544
1545         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1546         if (!ADS_ERR_OK(rc)) {
1547                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1548                 SAFE_FREE(prt_dn);
1549                 ads_destroy(&ads);
1550                 talloc_destroy(mem_ctx);
1551                 return -1;
1552         }
1553
1554         d_printf("published printer\n");
1555         SAFE_FREE(prt_dn);
1556         ads_destroy(&ads);
1557         talloc_destroy(mem_ctx);
1558
1559         return 0;
1560 }
1561
1562 static int net_ads_printer_remove(int argc, const char **argv)
1563 {
1564         ADS_STRUCT *ads;
1565         ADS_STATUS rc;
1566         const char *servername;
1567         char *prt_dn;
1568         LDAPMessage *res = NULL;
1569
1570         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1571                 return -1;
1572         }
1573
1574         if (argc < 1) {
1575                 return net_ads_printer_usage(argc, argv);
1576         }
1577
1578         if (argc > 1) {
1579                 servername = argv[1];
1580         } else {
1581                 servername = global_myname();
1582         }
1583
1584         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1585
1586         if (!ADS_ERR_OK(rc)) {
1587                 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1588                 ads_msgfree(ads, res);
1589                 ads_destroy(&ads);
1590                 return -1;
1591         }
1592
1593         if (ads_count_replies(ads, res) == 0) {
1594                 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1595                 ads_msgfree(ads, res);
1596                 ads_destroy(&ads);
1597                 return -1;
1598         }
1599
1600         prt_dn = ads_get_dn(ads, res);
1601         ads_msgfree(ads, res);
1602         rc = ads_del_dn(ads, prt_dn);
1603         ads_memfree(ads, prt_dn);
1604
1605         if (!ADS_ERR_OK(rc)) {
1606                 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1607                 ads_destroy(&ads);
1608                 return -1;
1609         }
1610
1611         ads_destroy(&ads);
1612         return 0;
1613 }
1614
1615 static int net_ads_printer(int argc, const char **argv)
1616 {
1617         struct functable func[] = {
1618                 {"SEARCH", net_ads_printer_search},
1619                 {"INFO", net_ads_printer_info},
1620                 {"PUBLISH", net_ads_printer_publish},
1621                 {"REMOVE", net_ads_printer_remove},
1622                 {NULL, NULL}
1623         };
1624
1625         return net_run_function(argc, argv, func, net_ads_printer_usage);
1626 }
1627
1628
1629 static int net_ads_password(int argc, const char **argv)
1630 {
1631         ADS_STRUCT *ads;
1632         const char *auth_principal = opt_user_name;
1633         const char *auth_password = opt_password;
1634         char *realm = NULL;
1635         char *new_password = NULL;
1636         char *c, *prompt;
1637         const char *user;
1638         ADS_STATUS ret;
1639
1640         if (opt_user_name == NULL || opt_password == NULL) {
1641                 d_fprintf(stderr, "You must supply an administrator username/password\n");
1642                 return -1;
1643         }
1644
1645         if (argc < 1) {
1646                 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1647                 return -1;
1648         }
1649
1650         user = argv[0];
1651         if (!strchr_m(user, '@')) {
1652                 asprintf(&c, "%s@%s", argv[0], lp_realm());
1653                 user = c;
1654         }
1655
1656         use_in_memory_ccache();
1657         c = strchr_m(auth_principal, '@');
1658         if (c) {
1659                 realm = ++c;
1660         } else {
1661                 realm = lp_realm();
1662         }
1663
1664         /* use the realm so we can eventually change passwords for users
1665         in realms other than default */
1666         if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1667                 return -1;
1668         }
1669
1670         /* we don't actually need a full connect, but it's the easy way to
1671                 fill in the KDC's addresss */
1672         ads_connect(ads);
1673
1674         if (!ads->config.realm) {
1675                 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1676                 return -1;
1677         }
1678
1679         if (argv[1]) {
1680                 new_password = (char *)argv[1];
1681         } else {
1682                 asprintf(&prompt, "Enter new password for %s:", user);
1683                 new_password = getpass(prompt);
1684                 free(prompt);
1685         }
1686
1687         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1688                                 auth_password, user, new_password, ads->auth.time_offset);
1689         if (!ADS_ERR_OK(ret)) {
1690                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1691                 ads_destroy(&ads);
1692                 return -1;
1693         }
1694
1695         d_printf("Password change for %s completed.\n", user);
1696         ads_destroy(&ads);
1697
1698         return 0;
1699 }
1700
1701 int net_ads_changetrustpw(int argc, const char **argv)
1702 {
1703         ADS_STRUCT *ads;
1704         char *host_principal;
1705         fstring my_name;
1706         ADS_STATUS ret;
1707
1708         if (!secrets_init()) {
1709                 DEBUG(1,("Failed to initialise secrets database\n"));
1710                 return -1;
1711         }
1712
1713         net_use_krb_machine_account();
1714
1715         use_in_memory_ccache();
1716
1717         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1718                 return -1;
1719         }
1720
1721         fstrcpy(my_name, global_myname());
1722         strlower_m(my_name);
1723         asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1724         d_printf("Changing password for principal: %s\n", host_principal);
1725
1726         ret = ads_change_trust_account_password(ads, host_principal);
1727
1728         if (!ADS_ERR_OK(ret)) {
1729                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1730                 ads_destroy(&ads);
1731                 SAFE_FREE(host_principal);
1732                 return -1;
1733         }
1734
1735         d_printf("Password change for principal %s succeeded.\n", host_principal);
1736
1737         if (lp_use_kerberos_keytab()) {
1738                 d_printf("Attempting to update system keytab with new password.\n");
1739                 if (ads_keytab_create_default(ads)) {
1740                         d_printf("Failed to update system keytab.\n");
1741                 }
1742         }
1743
1744         ads_destroy(&ads);
1745         SAFE_FREE(host_principal);
1746
1747         return 0;
1748 }
1749
1750 /*
1751   help for net ads search
1752 */
1753 static int net_ads_search_usage(int argc, const char **argv)
1754 {
1755         d_printf(
1756                 "\nnet ads search <expression> <attributes...>\n"\
1757                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1758                 "The expression is a standard LDAP search expression, and the\n"\
1759                 "attributes are a list of LDAP fields to show in the results\n\n"\
1760                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1761                 );
1762         net_common_flags_usage(argc, argv);
1763         return -1;
1764 }
1765
1766
1767 /*
1768   general ADS search function. Useful in diagnosing problems in ADS
1769 */
1770 static int net_ads_search(int argc, const char **argv)
1771 {
1772         ADS_STRUCT *ads;
1773         ADS_STATUS rc;
1774         const char *ldap_exp;
1775         const char **attrs;
1776         LDAPMessage *res = NULL;
1777
1778         if (argc < 1) {
1779                 return net_ads_search_usage(argc, argv);
1780         }
1781
1782         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1783                 return -1;
1784         }
1785
1786         ldap_exp = argv[0];
1787         attrs = (argv + 1);
1788
1789         rc = ads_do_search_all(ads, ads->config.bind_path,
1790                                LDAP_SCOPE_SUBTREE,
1791                                ldap_exp, attrs, &res);
1792         if (!ADS_ERR_OK(rc)) {
1793                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1794                 ads_destroy(&ads);
1795                 return -1;
1796         }
1797
1798         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1799
1800         /* dump the results */
1801         ads_dump(ads, res);
1802
1803         ads_msgfree(ads, res);
1804         ads_destroy(&ads);
1805
1806         return 0;
1807 }
1808
1809
1810 /*
1811   help for net ads search
1812 */
1813 static int net_ads_dn_usage(int argc, const char **argv)
1814 {
1815         d_printf(
1816                 "\nnet ads dn <dn> <attributes...>\n"\
1817                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1818                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1819                 "to show in the results\n\n"\
1820                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1821                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1822                 );
1823         net_common_flags_usage(argc, argv);
1824         return -1;
1825 }
1826
1827
1828 /*
1829   general ADS search function. Useful in diagnosing problems in ADS
1830 */
1831 static int net_ads_dn(int argc, const char **argv)
1832 {
1833         ADS_STRUCT *ads;
1834         ADS_STATUS rc;
1835         const char *dn;
1836         const char **attrs;
1837         LDAPMessage *res = NULL;
1838
1839         if (argc < 1) {
1840                 return net_ads_dn_usage(argc, argv);
1841         }
1842
1843         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1844                 return -1;
1845         }
1846
1847         dn = argv[0];
1848         attrs = (argv + 1);
1849
1850         rc = ads_do_search_all(ads, dn,
1851                                LDAP_SCOPE_BASE,
1852                                "(objectclass=*)", attrs, &res);
1853         if (!ADS_ERR_OK(rc)) {
1854                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1855                 ads_destroy(&ads);
1856                 return -1;
1857         }
1858
1859         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1860
1861         /* dump the results */
1862         ads_dump(ads, res);
1863
1864         ads_msgfree(ads, res);
1865         ads_destroy(&ads);
1866
1867         return 0;
1868 }
1869
1870 /*
1871   help for net ads sid search
1872 */
1873 static int net_ads_sid_usage(int argc, const char **argv)
1874 {
1875         d_printf(
1876                 "\nnet ads sid <sid> <attributes...>\n"\
1877                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1878                 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1879                 "to show in the results\n\n"\
1880                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1881                 );
1882         net_common_flags_usage(argc, argv);
1883         return -1;
1884 }
1885
1886
1887 /*
1888   general ADS search function. Useful in diagnosing problems in ADS
1889 */
1890 static int net_ads_sid(int argc, const char **argv)
1891 {
1892         ADS_STRUCT *ads;
1893         ADS_STATUS rc;
1894         const char *sid_string;
1895         const char **attrs;
1896         LDAPMessage *res = NULL;
1897         DOM_SID sid;
1898
1899         if (argc < 1) {
1900                 return net_ads_sid_usage(argc, argv);
1901         }
1902
1903         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1904                 return -1;
1905         }
1906
1907         sid_string = argv[0];
1908         attrs = (argv + 1);
1909
1910         if (!string_to_sid(&sid, sid_string)) {
1911                 d_fprintf(stderr, "could not convert sid\n");
1912                 ads_destroy(&ads);
1913                 return -1;
1914         }
1915
1916         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
1917         if (!ADS_ERR_OK(rc)) {
1918                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1919                 ads_destroy(&ads);
1920                 return -1;
1921         }
1922
1923         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1924
1925         /* dump the results */
1926         ads_dump(ads, res);
1927
1928         ads_msgfree(ads, res);
1929         ads_destroy(&ads);
1930
1931         return 0;
1932 }
1933
1934
1935 static int net_ads_keytab_usage(int argc, const char **argv)
1936 {
1937         d_printf(
1938                 "net ads keytab <COMMAND>\n"\
1939 "<COMMAND> can be either:\n"\
1940 "  ADD       Adds new service principal\n"\
1941 "  CREATE    Creates a fresh keytab\n"\
1942 "  FLUSH     Flushes out all keytab entries\n"\
1943 "  HELP      Prints this help message\n"\
1944 "  LIST      List the keytab\n"\
1945 "The ADD and LIST command will take arguments, the other commands\n"\
1946 "will not take any arguments.   The arguments given to ADD\n"\
1947 "should be a list of principals to add.  For example, \n"\
1948 "   net ads keytab add srv1 srv2\n"\
1949 "will add principals for the services srv1 and srv2 to the\n"\
1950 "system's keytab.\n"\
1951 "The LIST command takes a keytabname.\n"\
1952 "\n"
1953                 );
1954         return -1;
1955 }
1956
1957 static int net_ads_keytab_flush(int argc, const char **argv)
1958 {
1959         int ret;
1960         ADS_STRUCT *ads;
1961
1962         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1963                 return -1;
1964         }
1965         ret = ads_keytab_flush(ads);
1966         ads_destroy(&ads);
1967         return ret;
1968 }
1969
1970 static int net_ads_keytab_add(int argc, const char **argv)
1971 {
1972         int i;
1973         int ret = 0;
1974         ADS_STRUCT *ads;
1975
1976         d_printf("Processing principals to add...\n");
1977         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1978                 return -1;
1979         }
1980         for (i = 0; i < argc; i++) {
1981                 ret |= ads_keytab_add_entry(ads, argv[i]);
1982         }
1983         ads_destroy(&ads);
1984         return ret;
1985 }
1986
1987 static int net_ads_keytab_create(int argc, const char **argv)
1988 {
1989         ADS_STRUCT *ads;
1990         int ret;
1991
1992         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1993                 return -1;
1994         }
1995         ret = ads_keytab_create_default(ads);
1996         ads_destroy(&ads);
1997         return ret;
1998 }
1999
2000 static int net_ads_keytab_list(int argc, const char **argv)
2001 {
2002         const char *keytab = NULL;
2003
2004         if (argc >= 1) {
2005                 keytab = argv[0];
2006         }
2007
2008         return ads_keytab_list(keytab);
2009 }
2010
2011
2012 int net_ads_keytab(int argc, const char **argv)
2013 {
2014         struct functable func[] = {
2015                 {"ADD", net_ads_keytab_add},
2016                 {"CREATE", net_ads_keytab_create},
2017                 {"FLUSH", net_ads_keytab_flush},
2018                 {"HELP", net_ads_keytab_usage},
2019                 {"LIST", net_ads_keytab_list},
2020                 {NULL, NULL}
2021         };
2022
2023         if (!lp_use_kerberos_keytab()) {
2024                 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2025 use keytab functions.\n");
2026         }
2027
2028         return net_run_function(argc, argv, func, net_ads_keytab_usage);
2029 }
2030
2031 static int net_ads_kerberos_usage(int argc, const char **argv)
2032 {
2033         d_printf(
2034                 "net ads kerberos <COMMAND>\n"\
2035                 "<COMMAND> can be either:\n"\
2036                 "  RENEW     Renew TGT from existing credential cache\n"\
2037                 "  PAC       Dumps the Kerberos PAC\n"\
2038                 "  KINIT     Retrieve Ticket Granting Ticket (TGT)\n"\
2039                 "\n"
2040         );
2041
2042         return -1;
2043 }
2044
2045 static int net_ads_kerberos_renew(int argc, const char **argv)
2046 {
2047         int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2048         if (ret) {
2049                 d_printf("failed to renew kerberos ticket: %s\n",
2050                         error_message(ret));
2051         }
2052         return ret;
2053 }
2054
2055 static int net_ads_kerberos_pac(int argc, const char **argv)
2056 {
2057         struct PAC_DATA *pac = NULL;
2058         struct PAC_LOGON_INFO *info = NULL;
2059         TALLOC_CTX *mem_ctx = NULL;
2060         NTSTATUS status;
2061         int ret = -1;
2062
2063         mem_ctx = talloc_init("net_ads_kerberos_pac");
2064         if (!mem_ctx) {
2065                 goto out;
2066         }
2067
2068         opt_password = net_prompt_pass(opt_user_name);
2069
2070         status = kerberos_return_pac(mem_ctx,
2071                                      opt_user_name,
2072                                      opt_password,
2073                                      0,
2074                                      NULL,
2075                                      NULL,
2076                                      NULL,
2077                                      True,
2078                                      True,
2079                                      2592000, /* one month */
2080                                      &pac);
2081         if (!NT_STATUS_IS_OK(status)) {
2082                 d_printf("failed to query kerberos PAC: %s\n",
2083                         nt_errstr(status));
2084                 goto out;
2085         }
2086
2087         info = get_logon_info_from_pac(pac);
2088         if (info) {
2089                 const char *s;
2090                 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2091                 d_printf("The Pac: %s\n", s);
2092         }
2093
2094         ret = 0;
2095  out:
2096         TALLOC_FREE(mem_ctx);
2097         return ret;
2098 }
2099
2100 static int net_ads_kerberos_kinit(int argc, const char **argv)
2101 {
2102         TALLOC_CTX *mem_ctx = NULL;
2103         int ret = -1;
2104         NTSTATUS status;
2105
2106         mem_ctx = talloc_init("net_ads_kerberos_kinit");
2107         if (!mem_ctx) {
2108                 goto out;
2109         }
2110
2111         opt_password = net_prompt_pass(opt_user_name);
2112
2113         ret = kerberos_kinit_password_ext(opt_user_name,
2114                                           opt_password,
2115                                           0,
2116                                           NULL,
2117                                           NULL,
2118                                           NULL,
2119                                           True,
2120                                           True,
2121                                           2592000, /* one month */
2122                                           &status);
2123         if (ret) {
2124                 d_printf("failed to kinit password: %s\n",
2125                         nt_errstr(status));
2126         }
2127  out:
2128         return ret;
2129 }
2130
2131 int net_ads_kerberos(int argc, const char **argv)
2132 {
2133         struct functable func[] = {
2134                 {"KINIT", net_ads_kerberos_kinit},
2135                 {"RENEW", net_ads_kerberos_renew},
2136                 {"PAC", net_ads_kerberos_pac},
2137                 {"HELP", net_ads_kerberos_usage},
2138                 {NULL, NULL}
2139         };
2140
2141         return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2142 }
2143
2144
2145 int net_ads_help(int argc, const char **argv)
2146 {
2147         struct functable func[] = {
2148                 {"USER", net_ads_user_usage},
2149                 {"GROUP", net_ads_group_usage},
2150                 {"PRINTER", net_ads_printer_usage},
2151                 {"SEARCH", net_ads_search_usage},
2152                 {"INFO", net_ads_info},
2153                 {"JOIN", net_ads_join_usage},
2154                 {"DNS", net_ads_dns_usage},
2155                 {"LEAVE", net_ads_leave},
2156                 {"STATUS", net_ads_status},
2157                 {"PASSWORD", net_ads_password},
2158                 {"CHANGETRUSTPW", net_ads_changetrustpw},
2159                 {NULL, NULL}
2160         };
2161
2162         return net_run_function(argc, argv, func, net_ads_usage);
2163 }
2164
2165 int net_ads(int argc, const char **argv)
2166 {
2167         struct functable func[] = {
2168                 {"INFO", net_ads_info},
2169                 {"JOIN", net_ads_join},
2170                 {"TESTJOIN", net_ads_testjoin},
2171                 {"LEAVE", net_ads_leave},
2172                 {"STATUS", net_ads_status},
2173                 {"USER", net_ads_user},
2174                 {"GROUP", net_ads_group},
2175                 {"DNS", net_ads_dns},
2176                 {"PASSWORD", net_ads_password},
2177                 {"CHANGETRUSTPW", net_ads_changetrustpw},
2178                 {"PRINTER", net_ads_printer},
2179                 {"SEARCH", net_ads_search},
2180                 {"DN", net_ads_dn},
2181                 {"SID", net_ads_sid},
2182                 {"WORKGROUP", net_ads_workgroup},
2183                 {"LOOKUP", net_ads_lookup},
2184                 {"KEYTAB", net_ads_keytab},
2185                 {"GPO", net_ads_gpo},
2186                 {"KERBEROS", net_ads_kerberos},
2187                 {"HELP", net_ads_help},
2188                 {NULL, NULL}
2189         };
2190
2191         return net_run_function(argc, argv, func, net_ads_usage);
2192 }
2193
2194 #else
2195
2196 static int net_ads_noads(void)
2197 {
2198         d_fprintf(stderr, "ADS support not compiled in\n");
2199         return -1;
2200 }
2201
2202 int net_ads_keytab(int argc, const char **argv)
2203 {
2204         return net_ads_noads();
2205 }
2206
2207 int net_ads_kerberos(int argc, const char **argv)
2208 {
2209         return net_ads_noads();
2210 }
2211
2212 int net_ads_usage(int argc, const char **argv)
2213 {
2214         return net_ads_noads();
2215 }
2216
2217 int net_ads_help(int argc, const char **argv)
2218 {
2219         return net_ads_noads();
2220 }
2221
2222 int net_ads_changetrustpw(int argc, const char **argv)
2223 {
2224         return net_ads_noads();
2225 }
2226
2227 int net_ads_join(int argc, const char **argv)
2228 {
2229         return net_ads_noads();
2230 }
2231
2232 int net_ads_user(int argc, const char **argv)
2233 {
2234         return net_ads_noads();
2235 }
2236
2237 int net_ads_group(int argc, const char **argv)
2238 {
2239         return net_ads_noads();
2240 }
2241
2242 /* this one shouldn't display a message */
2243 int net_ads_check(void)
2244 {
2245         return -1;
2246 }
2247
2248 int net_ads_check_our_domain(void)
2249 {
2250         return -1;
2251 }
2252
2253 int net_ads(int argc, const char **argv)
2254 {
2255         return net_ads_usage(argc, argv);
2256 }
2257
2258 #endif  /* WITH_ADS */