sync 3.0 into HEAD for the last time
[samba.git] / source / utils / net_ads.c
1 /* 
2    Samba Unix/Linux SMB client library 
3    net ads commands
4    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
21 */
22
23 #include "includes.h"
24 #include "../utils/net.h"
25
26 #ifdef HAVE_ADS
27
28 int net_ads_usage(int argc, const char **argv)
29 {
30         d_printf(
31 "\nnet ads join <org_unit>"\
32 "\n\tjoins the local machine to a ADS realm\n"\
33 "\nnet ads leave"\
34 "\n\tremoves the local machine from a ADS realm\n"\
35 "\nnet ads testjoin"\
36 "\n\ttests that an exiting join is OK\n"\
37 "\nnet ads user"\
38 "\n\tlist, add, or delete users in the realm\n"\
39 "\nnet ads group"\
40 "\n\tlist, add, or delete groups in the realm\n"\
41 "\nnet ads info"\
42 "\n\tshows some info on the server\n"\
43 "\nnet ads status"\
44 "\n\tdump the machine account details to stdout\n"
45 "\nnet ads lookup"\
46 "\n\tperform a CLDAP search on the server\n"
47 "\nnet ads password <username@realm> -Uadmin_username@realm%%admin_pass"\
48 "\n\tchange a user's password using an admin account"\
49 "\n\t(note: use realm in UPPERCASE)\n"\
50 "\nnet ads changetrustpw"\
51 "\n\tchange the trust account password of this machine in the AD tree\n"\
52 "\nnet ads printer [info | publish | remove] <printername> <servername>"\
53 "\n\t lookup, add, or remove directory entry for a printer\n"\
54 "\nnet ads search"\
55 "\n\tperform a raw LDAP search and dump the results\n"
56 "\nnet ads dn"\
57 "\n\tperform a raw LDAP search and dump attributes of a particular DN\n"
58                 );
59         return -1;
60 }
61
62
63 /*
64   this implements the CLDAP based netlogon lookup requests
65   for finding the domain controller of a ADS domain
66 */
67 static int net_ads_lookup(int argc, const char **argv)
68 {
69         ADS_STRUCT *ads;
70
71         ads = ads_init(NULL, opt_target_workgroup, opt_host);
72         if (ads) {
73                 ads->auth.flags |= ADS_AUTH_NO_BIND;
74         }
75
76         ads_connect(ads);
77
78         if (!ads || !ads->config.realm) {
79                 d_printf("Didn't find the cldap server!\n");
80                 return -1;
81         }
82
83         return ads_cldap_netlogon(ads);
84 }
85
86
87
88 static int net_ads_info(int argc, const char **argv)
89 {
90         ADS_STRUCT *ads;
91
92         ads = ads_init(NULL, opt_target_workgroup, opt_host);
93
94         if (ads) {
95                 ads->auth.flags |= ADS_AUTH_NO_BIND;
96         }
97
98         ads_connect(ads);
99
100         if (!ads || !ads->config.realm) {
101                 d_printf("Didn't find the ldap server!\n");
102                 return -1;
103         }
104
105         d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
106         d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
107         d_printf("Realm: %s\n", ads->config.realm);
108         d_printf("Bind Path: %s\n", ads->config.bind_path);
109         d_printf("LDAP port: %d\n", ads->ldap_port);
110         d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
111
112        d_printf("KDC server: %s\n", ads->auth.kdc_server );
113        d_printf("Server time offset: %d\n", ads->auth.time_offset );
114
115         return 0;
116 }
117
118 static void use_in_memory_ccache(void) {
119         /* Use in-memory credentials cache so we do not interfere with
120          * existing credentials */
121         setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
122 }
123
124 static ADS_STRUCT *ads_startup(void)
125 {
126         ADS_STRUCT *ads;
127         ADS_STATUS status;
128         BOOL need_password = False;
129         BOOL second_time = False;
130         char *cp;
131         
132         /* lp_realm() should be handled by a command line param, 
133            However, the join requires that realm be set in smb.conf
134            and compares our realm with the remote server's so this is
135            ok until someone needs more flexibility */
136            
137         ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
138
139         if (!opt_user_name) {
140                 opt_user_name = "administrator";
141         }
142
143         if (opt_user_specified) {
144                 need_password = True;
145         }
146
147 retry:
148         if (!opt_password && need_password) {
149                 char *prompt;
150                 asprintf(&prompt,"%s password: ", opt_user_name);
151                 opt_password = getpass(prompt);
152                 free(prompt);
153         }
154
155         if (opt_password) {
156                 use_in_memory_ccache();
157                 ads->auth.password = smb_xstrdup(opt_password);
158         }
159
160         ads->auth.user_name = smb_xstrdup(opt_user_name);
161
162        /*
163         * If the username is of the form "name@realm", 
164         * extract the realm and convert to upper case.
165         * This is only used to establish the connection.
166         */
167        if ((cp = strchr(ads->auth.user_name, '@'))!=0) {
168                *cp++ = '\0';
169                ads->auth.realm = smb_xstrdup(cp);
170                strupper_m(ads->auth.realm);
171        }
172
173         status = ads_connect(ads);
174
175         if (!ADS_ERR_OK(status)) {
176                 if (!need_password && !second_time) {
177                         need_password = True;
178                         second_time = True;
179                         goto retry;
180                 } else {
181                         DEBUG(1,("ads_connect: %s\n", ads_errstr(status)));
182                         return NULL;
183                 }
184         }
185         return ads;
186 }
187
188
189 /*
190   Check to see if connection can be made via ads.
191   ads_startup() stores the password in opt_password if it needs to so
192   that rpc or rap can use it without re-prompting.
193 */
194 int net_ads_check(void)
195 {
196         ADS_STRUCT *ads;
197
198         ads = ads_startup();
199         if (!ads)
200                 return -1;
201         ads_destroy(&ads);
202         return 0;
203 }
204
205 /* 
206    determine the netbios workgroup name for a domain
207  */
208 static int net_ads_workgroup(int argc, const char **argv)
209 {
210         ADS_STRUCT *ads;
211         TALLOC_CTX *ctx;
212         char *workgroup;
213
214         if (!(ads = ads_startup())) return -1;
215
216         if (!(ctx = talloc_init("net_ads_workgroup"))) {
217                 return -1;
218         }
219
220         if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
221                 d_printf("Failed to find workgroup for realm '%s'\n", 
222                          ads->config.realm);
223                 talloc_destroy(ctx);
224                 return -1;
225         }
226
227         d_printf("Workgroup: %s\n", workgroup);
228
229         talloc_destroy(ctx);
230
231         return 0;
232 }
233
234
235
236 static BOOL usergrp_display(char *field, void **values, void *data_area)
237 {
238         char **disp_fields = (char **) data_area;
239
240         if (!field) { /* must be end of record */
241                 if (!strchr_m(disp_fields[0], '$')) {
242                         if (disp_fields[1])
243                                 d_printf("%-21.21s %s\n", 
244                                        disp_fields[0], disp_fields[1]);
245                         else
246                                 d_printf("%s\n", disp_fields[0]);
247                 }
248                 SAFE_FREE(disp_fields[0]);
249                 SAFE_FREE(disp_fields[1]);
250                 return True;
251         }
252         if (!values) /* must be new field, indicate string field */
253                 return True;
254         if (StrCaseCmp(field, "sAMAccountName") == 0) {
255                 disp_fields[0] = strdup((char *) values[0]);
256         }
257         if (StrCaseCmp(field, "description") == 0)
258                 disp_fields[1] = strdup((char *) values[0]);
259         return True;
260 }
261
262 static int net_ads_user_usage(int argc, const char **argv)
263 {
264         return net_help_user(argc, argv);
265
266
267 static int ads_user_add(int argc, const char **argv)
268 {
269         ADS_STRUCT *ads;
270         ADS_STATUS status;
271         char *upn, *userdn;
272         void *res=NULL;
273         int rc = -1;
274
275         if (argc < 1) return net_ads_user_usage(argc, argv);
276         
277         if (!(ads = ads_startup())) return -1;
278
279         status = ads_find_user_acct(ads, &res, argv[0]);
280
281         if (!ADS_ERR_OK(status)) {
282                 d_printf("ads_user_add: %s\n", ads_errstr(status));
283                 goto done;
284         }
285         
286         if (ads_count_replies(ads, res)) {
287                 d_printf("ads_user_add: User %s already exists\n", argv[0]);
288                 goto done;
289         }
290
291         status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
292
293         if (!ADS_ERR_OK(status)) {
294                 d_printf("Could not add user %s: %s\n", argv[0],
295                          ads_errstr(status));
296                 goto done;
297         }
298
299         /* if no password is to be set, we're done */
300         if (argc == 1) { 
301                 d_printf("User %s added\n", argv[0]);
302                 rc = 0;
303                 goto done;
304         }
305
306         /* try setting the password */
307         asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
308         status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1], 
309                                        ads->auth.time_offset);
310         safe_free(upn);
311         if (ADS_ERR_OK(status)) {
312                 d_printf("User %s added\n", argv[0]);
313                 rc = 0;
314                 goto done;
315         }
316
317         /* password didn't set, delete account */
318         d_printf("Could not add user %s.  Error setting password %s\n",
319                  argv[0], ads_errstr(status));
320         ads_msgfree(ads, res);
321         status=ads_find_user_acct(ads, &res, argv[0]);
322         if (ADS_ERR_OK(status)) {
323                 userdn = ads_get_dn(ads, res);
324                 ads_del_dn(ads, userdn);
325                 ads_memfree(ads, userdn);
326         }
327
328  done:
329         if (res)
330                 ads_msgfree(ads, res);
331         ads_destroy(&ads);
332         return rc;
333 }
334
335 static int ads_user_info(int argc, const char **argv)
336 {
337         ADS_STRUCT *ads;
338         ADS_STATUS rc;
339         void *res;
340         const char *attrs[] = {"memberOf", NULL};
341         char *searchstring=NULL;
342         char **grouplist;
343         char *escaped_user = escape_ldap_string_alloc(argv[0]);
344
345         if (argc < 1) return net_ads_user_usage(argc, argv);
346         
347         if (!(ads = ads_startup())) return -1;
348
349         if (!escaped_user) {
350                 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
351                 return -1;
352         }
353
354         asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
355         rc = ads_search(ads, &res, searchstring, attrs);
356         safe_free(searchstring);
357
358         if (!ADS_ERR_OK(rc)) {
359                 d_printf("ads_search: %s\n", ads_errstr(rc));
360                 return -1;
361         }
362         
363         grouplist = ldap_get_values(ads->ld, res, "memberOf");
364
365         if (grouplist) {
366                 int i;
367                 char **groupname;
368                 for (i=0;grouplist[i];i++) {
369                         groupname = ldap_explode_dn(grouplist[i], 1);
370                         d_printf("%s\n", groupname[0]);
371                         ldap_value_free(groupname);
372                 }
373                 ldap_value_free(grouplist);
374         }
375         
376         ads_msgfree(ads, res);
377
378         ads_destroy(&ads);
379         return 0;
380 }
381
382 static int ads_user_delete(int argc, const char **argv)
383 {
384         ADS_STRUCT *ads;
385         ADS_STATUS rc;
386         void *res;
387         char *userdn;
388
389         if (argc < 1) return net_ads_user_usage(argc, argv);
390         
391         if (!(ads = ads_startup())) return -1;
392
393         rc = ads_find_user_acct(ads, &res, argv[0]);
394         if (!ADS_ERR_OK(rc)) {
395                 DEBUG(0, ("User %s does not exist\n", argv[0]));
396                 return -1;
397         }
398         userdn = ads_get_dn(ads, res);
399         ads_msgfree(ads, res);
400         rc = ads_del_dn(ads, userdn);
401         ads_memfree(ads, userdn);
402         if (!ADS_ERR_OK(rc)) {
403                 d_printf("User %s deleted\n", argv[0]);
404                 return 0;
405         }
406         d_printf("Error deleting user %s: %s\n", argv[0], 
407                  ads_errstr(rc));
408         return -1;
409 }
410
411 int net_ads_user(int argc, const char **argv)
412 {
413         struct functable func[] = {
414                 {"ADD", ads_user_add},
415                 {"INFO", ads_user_info},
416                 {"DELETE", ads_user_delete},
417                 {NULL, NULL}
418         };
419         ADS_STRUCT *ads;
420         ADS_STATUS rc;
421         const char *shortattrs[] = {"sAMAccountName", NULL};
422         const char *longattrs[] = {"sAMAccountName", "description", NULL};
423         char *disp_fields[2] = {NULL, NULL};
424         
425         if (argc == 0) {
426                 if (!(ads = ads_startup())) return -1;
427
428                 if (opt_long_list_entries)
429                         d_printf("\nUser name             Comment"\
430                                  "\n-----------------------------\n");
431
432                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
433                                           LDAP_SCOPE_SUBTREE,
434                                           "(objectclass=user)", 
435                                           opt_long_list_entries ? longattrs :
436                                           shortattrs, usergrp_display, 
437                                           disp_fields);
438                 ads_destroy(&ads);
439                 return 0;
440         }
441
442         return net_run_function(argc, argv, func, net_ads_user_usage);
443 }
444
445 static int net_ads_group_usage(int argc, const char **argv)
446 {
447         return net_help_group(argc, argv);
448
449
450 static int ads_group_add(int argc, const char **argv)
451 {
452         ADS_STRUCT *ads;
453         ADS_STATUS status;
454         void *res=NULL;
455         int rc = -1;
456
457         if (argc < 1) return net_ads_group_usage(argc, argv);
458         
459         if (!(ads = ads_startup())) return -1;
460
461         status = ads_find_user_acct(ads, &res, argv[0]);
462
463         if (!ADS_ERR_OK(status)) {
464                 d_printf("ads_group_add: %s\n", ads_errstr(status));
465                 goto done;
466         }
467         
468         if (ads_count_replies(ads, res)) {
469                 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
470                 ads_msgfree(ads, res);
471                 goto done;
472         }
473
474         status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
475
476         if (ADS_ERR_OK(status)) {
477                 d_printf("Group %s added\n", argv[0]);
478                 rc = 0;
479         } else {
480                 d_printf("Could not add group %s: %s\n", argv[0],
481                          ads_errstr(status));
482         }
483
484  done:
485         if (res)
486                 ads_msgfree(ads, res);
487         ads_destroy(&ads);
488         return rc;
489 }
490
491 static int ads_group_delete(int argc, const char **argv)
492 {
493         ADS_STRUCT *ads;
494         ADS_STATUS rc;
495         void *res;
496         char *groupdn;
497
498         if (argc < 1) return net_ads_group_usage(argc, argv);
499         
500         if (!(ads = ads_startup())) return -1;
501
502         rc = ads_find_user_acct(ads, &res, argv[0]);
503         if (!ADS_ERR_OK(rc)) {
504                 DEBUG(0, ("Group %s does not exist\n", argv[0]));
505                 return -1;
506         }
507         groupdn = ads_get_dn(ads, res);
508         ads_msgfree(ads, res);
509         rc = ads_del_dn(ads, groupdn);
510         ads_memfree(ads, groupdn);
511         if (!ADS_ERR_OK(rc)) {
512                 d_printf("Group %s deleted\n", argv[0]);
513                 return 0;
514         }
515         d_printf("Error deleting group %s: %s\n", argv[0], 
516                  ads_errstr(rc));
517         return -1;
518 }
519
520 int net_ads_group(int argc, const char **argv)
521 {
522         struct functable func[] = {
523                 {"ADD", ads_group_add},
524                 {"DELETE", ads_group_delete},
525                 {NULL, NULL}
526         };
527         ADS_STRUCT *ads;
528         ADS_STATUS rc;
529         const char *shortattrs[] = {"sAMAccountName", NULL};
530         const char *longattrs[] = {"sAMAccountName", "description", NULL};
531         char *disp_fields[2] = {NULL, NULL};
532
533         if (argc == 0) {
534                 if (!(ads = ads_startup())) return -1;
535
536                 if (opt_long_list_entries)
537                         d_printf("\nGroup name            Comment"\
538                                  "\n-----------------------------\n");
539                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
540                                           LDAP_SCOPE_SUBTREE, 
541                                           "(objectclass=group)", 
542                                           opt_long_list_entries ? longattrs : 
543                                           shortattrs, usergrp_display, 
544                                           disp_fields);
545
546                 ads_destroy(&ads);
547                 return 0;
548         }
549         return net_run_function(argc, argv, func, net_ads_group_usage);
550 }
551
552 static int net_ads_status(int argc, const char **argv)
553 {
554         ADS_STRUCT *ads;
555         ADS_STATUS rc;
556         void *res;
557
558         if (!(ads = ads_startup())) return -1;
559
560         rc = ads_find_machine_acct(ads, &res, global_myname());
561         if (!ADS_ERR_OK(rc)) {
562                 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
563                 return -1;
564         }
565
566         if (ads_count_replies(ads, res) == 0) {
567                 d_printf("No machine account for '%s' found\n", global_myname());
568                 return -1;
569         }
570
571         ads_dump(ads, res);
572
573         return 0;
574 }
575
576 static int net_ads_leave(int argc, const char **argv)
577 {
578         ADS_STRUCT *ads = NULL;
579         ADS_STATUS rc;
580
581         if (!secrets_init()) {
582                 DEBUG(1,("Failed to initialise secrets database\n"));
583                 return -1;
584         }
585
586         if (!opt_password) {
587                 net_use_machine_password();
588         }
589
590         if (!(ads = ads_startup())) {
591                 return -1;
592         }
593
594         rc = ads_leave_realm(ads, global_myname());
595         if (!ADS_ERR_OK(rc)) {
596             d_printf("Failed to delete host '%s' from the '%s' realm.\n", 
597                      global_myname(), ads->config.realm);
598             return -1;
599         }
600
601         d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
602
603         return 0;
604 }
605
606 static int net_ads_join_ok(void)
607 {
608         ADS_STRUCT *ads = NULL;
609
610         if (!secrets_init()) {
611                 DEBUG(1,("Failed to initialise secrets database\n"));
612                 return -1;
613         }
614
615         net_use_machine_password();
616
617         if (!(ads = ads_startup())) {
618                 return -1;
619         }
620
621         ads_destroy(&ads);
622         return 0;
623 }
624
625 /*
626   check that an existing join is OK
627  */
628 int net_ads_testjoin(int argc, const char **argv)
629 {
630         use_in_memory_ccache();
631
632         /* Display success or failure */
633         if (net_ads_join_ok() != 0) {
634                 fprintf(stderr,"Join to domain is not valid\n");
635                 return -1;
636         }
637
638         printf("Join is OK\n");
639         return 0;
640 }
641
642 /*
643   join a domain using ADS
644  */
645 int net_ads_join(int argc, const char **argv)
646 {
647         ADS_STRUCT *ads;
648         ADS_STATUS rc;
649         char *password;
650         char *machine_account = NULL;
651         char *tmp_password;
652         const char *org_unit = "Computers";
653         char *dn;
654         void *res;
655         DOM_SID dom_sid;
656         char *ou_str;
657         uint32 sec_channel_type = SEC_CHAN_WKSTA;
658         uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
659         char *short_domain_name = NULL;
660         TALLOC_CTX *ctx = NULL;
661
662         if (argc > 0) org_unit = argv[0];
663
664         if (!secrets_init()) {
665                 DEBUG(1,("Failed to initialise secrets database\n"));
666                 return -1;
667         }
668
669         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
670         password = strdup(tmp_password);
671
672         if (!(ads = ads_startup())) return -1;
673
674         if (!*lp_realm()) {
675                 d_printf("realm must be set in in smb.conf for ADS join to succeed.\n");
676                 return -1;
677         }
678
679         if (strcmp(ads->config.realm, lp_realm()) != 0) {
680                 d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match.  Aborting join\n", ads->config.realm, lp_realm());
681                 return -1;
682         }
683
684         ou_str = ads_ou_string(org_unit);
685         asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
686         free(ou_str);
687
688         rc = ads_search_dn(ads, &res, dn, NULL);
689         ads_msgfree(ads, res);
690
691         if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
692                 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", 
693                          org_unit, dn);
694                 return -1;
695         }
696         free(dn);
697
698         if (!ADS_ERR_OK(rc)) {
699                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
700                 return -1;
701         }       
702
703         rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
704         if (!ADS_ERR_OK(rc)) {
705                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
706                 return -1;
707         }
708
709         rc = ads_domain_sid(ads, &dom_sid);
710         if (!ADS_ERR_OK(rc)) {
711                 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));       
712         return -1;
713         }
714
715         if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
716                 d_printf("asprintf failed\n");
717                 return -1;
718         }
719
720         rc = ads_set_machine_password(ads, machine_account, password);
721         if (!ADS_ERR_OK(rc)) {
722                 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
723                 return -1;
724         }
725         
726         /* make sure we get the right workgroup */
727         
728         if ( !(ctx = talloc_init("net ads join")) ) {
729                 d_printf("talloc_init() failed!\n");
730                 return -1;
731         }
732         
733         rc = ads_workgroup_name(ads, ctx, &short_domain_name);
734         if ( ADS_ERR_OK(rc) ) {
735                 if ( !strequal(lp_workgroup(), short_domain_name) ) {
736                         d_printf("The workgroup in smb.conf does not match the short\n");
737                         d_printf("domain name obtained from the server.\n");
738                         d_printf("Using the name [%s] from the server.\n", short_domain_name);
739                         d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
740                 }
741         }
742         else
743                 short_domain_name = lp_workgroup();
744         
745         d_printf("Using short domain name -- %s\n", short_domain_name);
746         
747         /*  HACK ALRET!  Store the sid and password under bother the lp_workgroup() 
748             value from smb.conf and the string returned from the server.  The former is
749             neede to bootstrap winbindd's first connection to the DC to get the real 
750             short domain name   --jerry */
751             
752         if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
753                 DEBUG(1,("Failed to save domain sid\n"));
754                 return -1;
755         }
756
757         if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
758                 DEBUG(1,("Failed to save machine password\n"));
759                 return -1;
760         }
761
762         if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
763                 DEBUG(1,("Failed to save domain sid\n"));
764                 return -1;
765         }
766
767         if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
768                 DEBUG(1,("Failed to save machine password\n"));
769                 return -1;
770         }
771         
772         d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
773
774         SAFE_FREE(password);
775         SAFE_FREE(machine_account);
776         if ( ctx )
777                 talloc_destroy(ctx);
778         return 0;
779 }
780
781 int net_ads_printer_usage(int argc, const char **argv)
782 {
783         d_printf(
784 "\nnet ads printer search <printer>"
785 "\n\tsearch for a printer in the directory"
786 "\nnet ads printer info <printer> <server>"
787 "\n\tlookup info in directory for printer on server"
788 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
789 "\nnet ads printer publish <printername>"
790 "\n\tpublish printer in directory"
791 "\n\t(note: printer name is required)\n"
792 "\nnet ads printer remove <printername>"
793 "\n\tremove printer from directory"
794 "\n\t(note: printer name is required)\n");
795         return -1;
796 }
797
798 static int net_ads_printer_search(int argc, const char **argv)
799 {
800         ADS_STRUCT *ads;
801         ADS_STATUS rc;
802         void *res = NULL;
803
804         if (!(ads = ads_startup())) 
805                 return -1;
806
807         rc = ads_find_printers(ads, &res);
808
809         if (!ADS_ERR_OK(rc)) {
810                 d_printf("ads_find_printer: %s\n", ads_errstr(rc));
811                 ads_msgfree(ads, res);
812                 return -1;
813         }
814
815         if (ads_count_replies(ads, res) == 0) {
816                 d_printf("No results found\n");
817                 ads_msgfree(ads, res);
818                 return -1;
819         }
820
821         ads_dump(ads, res);
822         ads_msgfree(ads, res);
823
824         return 0;
825 }
826
827 static int net_ads_printer_info(int argc, const char **argv)
828 {
829         ADS_STRUCT *ads;
830         ADS_STATUS rc;
831         const char *servername, *printername;
832         void *res = NULL;
833
834         if (!(ads = ads_startup())) return -1;
835
836         if (argc > 0)
837                 printername = argv[0];
838         else
839                 printername = "*";
840
841         if (argc > 1)
842                 servername =  argv[1];
843         else
844                 servername = global_myname();
845
846         rc = ads_find_printer_on_server(ads, &res, printername, servername);
847
848         if (!ADS_ERR_OK(rc)) {
849                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
850                 ads_msgfree(ads, res);
851                 return -1;
852         }
853
854         if (ads_count_replies(ads, res) == 0) {
855                 d_printf("Printer '%s' not found\n", printername);
856                 ads_msgfree(ads, res);
857                 return -1;
858         }
859
860         ads_dump(ads, res);
861         ads_msgfree(ads, res);
862
863         return 0;
864 }
865
866 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
867 {
868         return;
869 }
870
871 static int net_ads_printer_publish(int argc, const char **argv)
872 {
873         ADS_STRUCT *ads;
874         ADS_STATUS rc;
875         const char *servername, *printername;
876         struct cli_state *cli;
877         struct in_addr          server_ip;
878         NTSTATUS nt_status;
879         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
880         ADS_MODLIST mods = ads_init_mods(mem_ctx);
881         char *prt_dn, *srv_dn, **srv_cn;
882         void *res = NULL;
883
884         if (!(ads = ads_startup())) return -1;
885
886         if (argc < 1)
887                 return net_ads_printer_usage(argc, argv);
888         
889         printername = argv[0];
890
891         if (argc == 2)
892                 servername = argv[1];
893         else
894                 servername = global_myname();
895                 
896         /* Get printer data from SPOOLSS */
897
898         resolve_name(servername, &server_ip, 0x20);
899
900         nt_status = cli_full_connection(&cli, global_myname(), servername, 
901                                         &server_ip, 0,
902                                         "IPC$", "IPC",  
903                                         opt_user_name, opt_workgroup,
904                                         opt_password ? opt_password : "", 
905                                         CLI_FULL_CONNECTION_USE_KERBEROS, 
906                                         Undefined, NULL);
907
908         if (NT_STATUS_IS_ERR(nt_status)) {
909                 d_printf("Unable to open a connnection to %s to obtain data "
910                          "for %s\n", servername, printername);
911                 return -1;
912         }
913
914         /* Publish on AD server */
915
916         ads_find_machine_acct(ads, &res, servername);
917
918         if (ads_count_replies(ads, res) == 0) {
919                 d_printf("Could not find machine account for server %s\n", 
920                          servername);
921                 return -1;
922         }
923
924         srv_dn = ldap_get_dn(ads->ld, res);
925         srv_cn = ldap_explode_dn(srv_dn, 1);
926
927         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
928
929         cli_nt_session_open(cli, PI_SPOOLSS);
930         get_remote_printer_publishing_data(cli, mem_ctx, &mods, printername);
931
932         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
933         if (!ADS_ERR_OK(rc)) {
934                 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
935                 return -1;
936         }
937  
938         d_printf("published printer\n");
939  
940         return 0;
941 }
942
943 static int net_ads_printer_remove(int argc, const char **argv)
944 {
945         ADS_STRUCT *ads;
946         ADS_STATUS rc;
947         const char *servername;
948         char *prt_dn;
949         void *res = NULL;
950
951         if (!(ads = ads_startup())) return -1;
952
953         if (argc < 1)
954                 return net_ads_printer_usage(argc, argv);
955
956         if (argc > 1)
957                 servername = argv[1];
958         else
959                 servername = global_myname();
960
961         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
962
963         if (!ADS_ERR_OK(rc)) {
964                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
965                 ads_msgfree(ads, res);
966                 return -1;
967         }
968
969         if (ads_count_replies(ads, res) == 0) {
970                 d_printf("Printer '%s' not found\n", argv[1]);
971                 ads_msgfree(ads, res);
972                 return -1;
973         }
974
975         prt_dn = ads_get_dn(ads, res);
976         ads_msgfree(ads, res);
977         rc = ads_del_dn(ads, prt_dn);
978         ads_memfree(ads, prt_dn);
979
980         if (!ADS_ERR_OK(rc)) {
981                 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
982                 return -1;
983         }
984
985         return 0;
986 }
987
988 static int net_ads_printer(int argc, const char **argv)
989 {
990         struct functable func[] = {
991                 {"SEARCH", net_ads_printer_search},
992                 {"INFO", net_ads_printer_info},
993                 {"PUBLISH", net_ads_printer_publish},
994                 {"REMOVE", net_ads_printer_remove},
995                 {NULL, NULL}
996         };
997         
998         return net_run_function(argc, argv, func, net_ads_printer_usage);
999 }
1000
1001
1002 static int net_ads_password(int argc, const char **argv)
1003 {
1004     ADS_STRUCT *ads;
1005     const char *auth_principal = opt_user_name;
1006     const char *auth_password = opt_password;
1007     char *realm = NULL;
1008     char *new_password = NULL;
1009     char *c, *prompt;
1010     const char *user;
1011     ADS_STATUS ret;
1012
1013     if (opt_user_name == NULL || opt_password == NULL) {
1014             d_printf("You must supply an administrator username/password\n");
1015             return -1;
1016     }
1017
1018     
1019     if (argc != 1) {
1020             d_printf("ERROR: You must say which username to change password for\n");
1021             return -1;
1022     }
1023
1024     user = argv[0];
1025     if (!strchr(user, '@')) {
1026             asprintf(&c, "%s@%s", argv[0], lp_realm());
1027             user = c;
1028     }
1029
1030     use_in_memory_ccache();    
1031     c = strchr(auth_principal, '@');
1032     if (c) {
1033             realm = ++c;
1034     } else {
1035             realm = lp_realm();
1036     }
1037
1038     /* use the realm so we can eventually change passwords for users 
1039     in realms other than default */
1040     if (!(ads = ads_init(realm, NULL, NULL))) return -1;
1041
1042     /* we don't actually need a full connect, but it's the easy way to
1043        fill in the KDC's addresss */
1044     ads_connect(ads);
1045     
1046     if (!ads || !ads->config.realm) {
1047             d_printf("Didn't find the kerberos server!\n");
1048             return -1;
1049     }
1050
1051     asprintf(&prompt, "Enter new password for %s:", user);
1052
1053     new_password = getpass(prompt);
1054
1055     ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
1056                                 auth_password, user, new_password, ads->auth.time_offset);
1057     if (!ADS_ERR_OK(ret)) {
1058         d_printf("Password change failed :-( ...\n");
1059         ads_destroy(&ads);
1060         free(prompt);
1061         return -1;
1062     }
1063
1064     d_printf("Password change for %s completed.\n", user);
1065     ads_destroy(&ads);
1066     free(prompt);
1067
1068     return 0;
1069 }
1070
1071
1072 int net_ads_changetrustpw(int argc, const char **argv)
1073 {    
1074     ADS_STRUCT *ads;
1075     char *host_principal;
1076     char *hostname;
1077     ADS_STATUS ret;
1078
1079     if (!secrets_init()) {
1080             DEBUG(1,("Failed to initialise secrets database\n"));
1081             return -1;
1082     }
1083
1084     net_use_machine_password();
1085
1086     use_in_memory_ccache();
1087
1088     if (!(ads = ads_startup())) {
1089             return -1;
1090     }
1091
1092     hostname = strdup(global_myname());
1093     strlower_m(hostname);
1094     asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
1095     SAFE_FREE(hostname);
1096     d_printf("Changing password for principal: HOST/%s\n", host_principal);
1097     
1098     ret = ads_change_trust_account_password(ads, host_principal);
1099
1100     if (!ADS_ERR_OK(ret)) {
1101         d_printf("Password change failed :-( ...\n");
1102         ads_destroy(&ads);
1103         SAFE_FREE(host_principal);
1104         return -1;
1105     }
1106     
1107     d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1108     ads_destroy(&ads);
1109     SAFE_FREE(host_principal);
1110
1111     return 0;
1112 }
1113
1114 /*
1115   help for net ads search
1116 */
1117 static int net_ads_search_usage(int argc, const char **argv)
1118 {
1119         d_printf(
1120                 "\nnet ads search <expression> <attributes...>\n"\
1121                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1122                 "The expression is a standard LDAP search expression, and the\n"\
1123                 "attributes are a list of LDAP fields to show in the results\n\n"\
1124                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1125                 );
1126         net_common_flags_usage(argc, argv);
1127         return -1;
1128 }
1129
1130
1131 /*
1132   general ADS search function. Useful in diagnosing problems in ADS
1133 */
1134 static int net_ads_search(int argc, const char **argv)
1135 {
1136         ADS_STRUCT *ads;
1137         ADS_STATUS rc;
1138         const char *ldap_exp;
1139         const char **attrs;
1140         void *res = NULL;
1141
1142         if (argc < 1) {
1143                 return net_ads_search_usage(argc, argv);
1144         }
1145
1146         if (!(ads = ads_startup())) {
1147                 return -1;
1148         }
1149
1150         ldap_exp = argv[0];
1151         attrs = (argv + 1);
1152
1153         rc = ads_do_search_all(ads, ads->config.bind_path,
1154                                LDAP_SCOPE_SUBTREE,
1155                                ldap_exp, attrs, &res);
1156         if (!ADS_ERR_OK(rc)) {
1157                 d_printf("search failed: %s\n", ads_errstr(rc));
1158                 return -1;
1159         }       
1160
1161         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1162
1163         /* dump the results */
1164         ads_dump(ads, res);
1165
1166         ads_msgfree(ads, res);
1167         ads_destroy(&ads);
1168
1169         return 0;
1170 }
1171
1172
1173 /*
1174   help for net ads search
1175 */
1176 static int net_ads_dn_usage(int argc, const char **argv)
1177 {
1178         d_printf(
1179                 "\nnet ads dn <dn> <attributes...>\n"\
1180                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1181                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1182                 "to show in the results\n\n"\
1183                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1184                 );
1185         net_common_flags_usage(argc, argv);
1186         return -1;
1187 }
1188
1189
1190 /*
1191   general ADS search function. Useful in diagnosing problems in ADS
1192 */
1193 static int net_ads_dn(int argc, const char **argv)
1194 {
1195         ADS_STRUCT *ads;
1196         ADS_STATUS rc;
1197         const char *dn;
1198         const char **attrs;
1199         void *res = NULL;
1200
1201         if (argc < 1) {
1202                 return net_ads_dn_usage(argc, argv);
1203         }
1204
1205         if (!(ads = ads_startup())) {
1206                 return -1;
1207         }
1208
1209         dn = argv[0];
1210         attrs = (argv + 1);
1211
1212         rc = ads_do_search_all(ads, dn, 
1213                                LDAP_SCOPE_BASE,
1214                                "(objectclass=*)", attrs, &res);
1215         if (!ADS_ERR_OK(rc)) {
1216                 d_printf("search failed: %s\n", ads_errstr(rc));
1217                 return -1;
1218         }       
1219
1220         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1221
1222         /* dump the results */
1223         ads_dump(ads, res);
1224
1225         ads_msgfree(ads, res);
1226         ads_destroy(&ads);
1227
1228         return 0;
1229 }
1230
1231
1232 int net_ads_help(int argc, const char **argv)
1233 {
1234         struct functable func[] = {
1235                 {"USER", net_ads_user_usage},
1236                 {"GROUP", net_ads_group_usage},
1237                 {"PRINTER", net_ads_printer_usage},
1238                 {"SEARCH", net_ads_search_usage},
1239 #if 0
1240                 {"INFO", net_ads_info},
1241                 {"JOIN", net_ads_join},
1242                 {"LEAVE", net_ads_leave},
1243                 {"STATUS", net_ads_status},
1244                 {"PASSWORD", net_ads_password},
1245                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1246 #endif
1247                 {NULL, NULL}
1248         };
1249
1250         return net_run_function(argc, argv, func, net_ads_usage);
1251 }
1252
1253 int net_ads(int argc, const char **argv)
1254 {
1255         struct functable func[] = {
1256                 {"INFO", net_ads_info},
1257                 {"JOIN", net_ads_join},
1258                 {"TESTJOIN", net_ads_testjoin},
1259                 {"LEAVE", net_ads_leave},
1260                 {"STATUS", net_ads_status},
1261                 {"USER", net_ads_user},
1262                 {"GROUP", net_ads_group},
1263                 {"PASSWORD", net_ads_password},
1264                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1265                 {"PRINTER", net_ads_printer},
1266                 {"SEARCH", net_ads_search},
1267                 {"DN", net_ads_dn},
1268                 {"WORKGROUP", net_ads_workgroup},
1269                 {"LOOKUP", net_ads_lookup},
1270                 {"HELP", net_ads_help},
1271                 {NULL, NULL}
1272         };
1273         
1274         return net_run_function(argc, argv, func, net_ads_usage);
1275 }
1276
1277 #else
1278
1279 static int net_ads_noads(void)
1280 {
1281         d_printf("ADS support not compiled in\n");
1282         return -1;
1283 }
1284
1285 int net_ads_usage(int argc, const char **argv)
1286 {
1287         return net_ads_noads();
1288 }
1289
1290 int net_ads_help(int argc, const char **argv)
1291 {
1292         return net_ads_noads();
1293 }
1294
1295 int net_ads_changetrustpw(int argc, const char **argv)
1296 {
1297         return net_ads_noads();
1298 }
1299
1300 int net_ads_join(int argc, const char **argv)
1301 {
1302         return net_ads_noads();
1303 }
1304
1305 int net_ads_user(int argc, const char **argv)
1306 {
1307         return net_ads_noads();
1308 }
1309
1310 int net_ads_group(int argc, const char **argv)
1311 {
1312         return net_ads_noads();
1313 }
1314
1315 /* this one shouldn't display a message */
1316 int net_ads_check(void)
1317 {
1318         return -1;
1319 }
1320
1321 int net_ads(int argc, const char **argv)
1322 {
1323         return net_ads_usage(argc, argv);
1324 }
1325
1326 #endif