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