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