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