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