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