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