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