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