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