This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[jra/samba/.git] / source3 / utils / net_ads.c
1 /* 
2    Samba Unix/Linux SMB client library 
3    net ads commands
4    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7
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, NULL, 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, NULL, 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         return 0;
113 }
114
115 static void use_in_memory_ccache(void) {
116         /* Use in-memory credentials cache so we do not interfere with
117          * existing credentials */
118         setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
119 }
120
121 static ADS_STRUCT *ads_startup(void)
122 {
123         ADS_STRUCT *ads;
124         ADS_STATUS status;
125         BOOL need_password = False;
126         BOOL second_time = False;
127         
128         ads = ads_init(NULL, NULL, opt_host);
129
130         if (!opt_user_name) {
131                 opt_user_name = "administrator";
132         }
133
134         if (opt_user_specified) {
135                 need_password = True;
136         }
137
138 retry:
139         if (!opt_password && need_password) {
140                 char *prompt;
141                 asprintf(&prompt,"%s password: ", opt_user_name);
142                 opt_password = getpass(prompt);
143                 free(prompt);
144         }
145
146         if (opt_password) {
147                 use_in_memory_ccache();
148                 ads->auth.password = strdup(opt_password);
149         }
150
151         ads->auth.user_name = strdup(opt_user_name);
152
153         status = ads_connect(ads);
154         if (!ADS_ERR_OK(status)) {
155                 if (!need_password && !second_time) {
156                         need_password = True;
157                         second_time = True;
158                         goto retry;
159                 } else {
160                         DEBUG(1,("ads_connect: %s\n", ads_errstr(status)));
161                         return NULL;
162                 }
163         }
164         return ads;
165 }
166
167
168 /*
169   Check to see if connection can be made via ads.
170   ads_startup() stores the password in opt_password if it needs to so
171   that rpc or rap can use it without re-prompting.
172 */
173 int net_ads_check(void)
174 {
175         ADS_STRUCT *ads;
176
177         ads = ads_startup();
178         if (!ads)
179                 return -1;
180         ads_destroy(&ads);
181         return 0;
182 }
183
184 /* 
185    determine the netbios workgroup name for a domain
186  */
187 static int net_ads_workgroup(int argc, const char **argv)
188 {
189         ADS_STRUCT *ads;
190         TALLOC_CTX *ctx;
191         char *workgroup;
192
193         if (!(ads = ads_startup())) return -1;
194
195         if (!(ctx = talloc_init("net_ads_workgroup"))) {
196                 return -1;
197         }
198
199         if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
200                 d_printf("Failed to find workgroup for realm '%s'\n", 
201                          ads->config.realm);
202                 talloc_destroy(ctx);
203                 return -1;
204         }
205
206         d_printf("Workgroup: %s\n", workgroup);
207
208         talloc_destroy(ctx);
209
210         return 0;
211 }
212
213
214
215 static BOOL usergrp_display(char *field, void **values, void *data_area)
216 {
217         char **disp_fields = (char **) data_area;
218
219         if (!field) { /* must be end of record */
220                 if (!strchr_m(disp_fields[0], '$')) {
221                         if (disp_fields[1])
222                                 d_printf("%-21.21s %-50.50s\n", 
223                                        disp_fields[0], disp_fields[1]);
224                         else
225                                 d_printf("%s\n", disp_fields[0]);
226                 }
227                 SAFE_FREE(disp_fields[0]);
228                 SAFE_FREE(disp_fields[1]);
229                 return True;
230         }
231         if (!values) /* must be new field, indicate string field */
232                 return True;
233         if (StrCaseCmp(field, "sAMAccountName") == 0) {
234                 disp_fields[0] = strdup((char *) values[0]);
235         }
236         if (StrCaseCmp(field, "description") == 0)
237                 disp_fields[1] = strdup((char *) values[0]);
238         return True;
239 }
240
241 static int net_ads_user_usage(int argc, const char **argv)
242 {
243         return net_help_user(argc, argv);
244
245
246 static int ads_user_add(int argc, const char **argv)
247 {
248         ADS_STRUCT *ads;
249         ADS_STATUS status;
250         char *upn, *userdn;
251         void *res=NULL;
252         int rc = -1;
253
254         if (argc < 1) return net_ads_user_usage(argc, argv);
255         
256         if (!(ads = ads_startup())) return -1;
257
258         status = ads_find_user_acct(ads, &res, argv[0]);
259
260         if (!ADS_ERR_OK(status)) {
261                 d_printf("ads_user_add: %s\n", ads_errstr(status));
262                 goto done;
263         }
264         
265         if (ads_count_replies(ads, res)) {
266                 d_printf("ads_user_add: User %s already exists\n", argv[0]);
267                 goto done;
268         }
269
270         status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
271
272         if (!ADS_ERR_OK(status)) {
273                 d_printf("Could not add user %s: %s\n", argv[0],
274                          ads_errstr(status));
275                 goto done;
276         }
277
278         /* if no password is to be set, we're done */
279         if (argc == 1) { 
280                 d_printf("User %s added\n", argv[0]);
281                 rc = 0;
282                 goto done;
283         }
284
285         /* try setting the password */
286         asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
287         status = krb5_set_password(ads->auth.kdc_server, upn, argv[1], ads->auth.time_offset);
288         safe_free(upn);
289         if (ADS_ERR_OK(status)) {
290                 d_printf("User %s added\n", argv[0]);
291                 rc = 0;
292                 goto done;
293         }
294
295         /* password didn't set, delete account */
296         d_printf("Could not add user %s.  Error setting password %s\n",
297                  argv[0], ads_errstr(status));
298         ads_msgfree(ads, res);
299         status=ads_find_user_acct(ads, &res, argv[0]);
300         if (ADS_ERR_OK(status)) {
301                 userdn = ads_get_dn(ads, res);
302                 ads_del_dn(ads, userdn);
303                 ads_memfree(ads, userdn);
304         }
305
306  done:
307         if (res)
308                 ads_msgfree(ads, res);
309         ads_destroy(&ads);
310         return rc;
311 }
312
313 static int ads_user_info(int argc, const char **argv)
314 {
315         ADS_STRUCT *ads;
316         ADS_STATUS rc;
317         void *res;
318         const char *attrs[] = {"memberOf", NULL};
319         char *searchstring=NULL;
320         char **grouplist;
321         char *escaped_user = escape_ldap_string_alloc(argv[0]);
322
323         if (argc < 1) return net_ads_user_usage(argc, argv);
324         
325         if (!(ads = ads_startup())) return -1;
326
327         if (!escaped_user) {
328                 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
329                 return -1;
330         }
331
332         asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
333         rc = ads_search(ads, &res, searchstring, attrs);
334         safe_free(searchstring);
335
336         if (!ADS_ERR_OK(rc)) {
337                 d_printf("ads_search: %s\n", ads_errstr(rc));
338                 return -1;
339         }
340         
341         grouplist = ldap_get_values(ads->ld, res, "memberOf");
342
343         if (grouplist) {
344                 int i;
345                 char **groupname;
346                 for (i=0;grouplist[i];i++) {
347                         groupname = ldap_explode_dn(grouplist[i], 1);
348                         d_printf("%s\n", groupname[0]);
349                         ldap_value_free(groupname);
350                 }
351                 ldap_value_free(grouplist);
352         }
353         
354         ads_msgfree(ads, res);
355
356         ads_destroy(&ads);
357         return 0;
358 }
359
360 static int ads_user_delete(int argc, const char **argv)
361 {
362         ADS_STRUCT *ads;
363         ADS_STATUS rc;
364         void *res;
365         char *userdn;
366
367         if (argc < 1) return net_ads_user_usage(argc, argv);
368         
369         if (!(ads = ads_startup())) return -1;
370
371         rc = ads_find_user_acct(ads, &res, argv[0]);
372         if (!ADS_ERR_OK(rc)) {
373                 DEBUG(0, ("User %s does not exist\n", argv[0]));
374                 return -1;
375         }
376         userdn = ads_get_dn(ads, res);
377         ads_msgfree(ads, res);
378         rc = ads_del_dn(ads, userdn);
379         ads_memfree(ads, userdn);
380         if (!ADS_ERR_OK(rc)) {
381                 d_printf("User %s deleted\n", argv[0]);
382                 return 0;
383         }
384         d_printf("Error deleting user %s: %s\n", argv[0], 
385                  ads_errstr(rc));
386         return -1;
387 }
388
389 int net_ads_user(int argc, const char **argv)
390 {
391         struct functable func[] = {
392                 {"ADD", ads_user_add},
393                 {"INFO", ads_user_info},
394                 {"DELETE", ads_user_delete},
395                 {NULL, NULL}
396         };
397         ADS_STRUCT *ads;
398         ADS_STATUS rc;
399         const char *shortattrs[] = {"sAMAccountName", NULL};
400         const char *longattrs[] = {"sAMAccountName", "description", NULL};
401         char *disp_fields[2] = {NULL, NULL};
402         
403         if (argc == 0) {
404                 if (!(ads = ads_startup())) return -1;
405
406                 if (opt_long_list_entries)
407                         d_printf("\nUser name             Comment"\
408                                  "\n-----------------------------\n");
409
410                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
411                                           LDAP_SCOPE_SUBTREE,
412                                           "(objectclass=user)", 
413                                           opt_long_list_entries ? longattrs :
414                                           shortattrs, usergrp_display, 
415                                           disp_fields);
416                 ads_destroy(&ads);
417                 return 0;
418         }
419
420         return net_run_function(argc, argv, func, net_ads_user_usage);
421 }
422
423 static int net_ads_group_usage(int argc, const char **argv)
424 {
425         return net_help_group(argc, argv);
426
427
428 static int ads_group_add(int argc, const char **argv)
429 {
430         ADS_STRUCT *ads;
431         ADS_STATUS status;
432         void *res=NULL;
433         int rc = -1;
434
435         if (argc < 1) return net_ads_group_usage(argc, argv);
436         
437         if (!(ads = ads_startup())) return -1;
438
439         status = ads_find_user_acct(ads, &res, argv[0]);
440
441         if (!ADS_ERR_OK(status)) {
442                 d_printf("ads_group_add: %s\n", ads_errstr(status));
443                 goto done;
444         }
445         
446         if (ads_count_replies(ads, res)) {
447                 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
448                 ads_msgfree(ads, res);
449                 goto done;
450         }
451
452         status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
453
454         if (ADS_ERR_OK(status)) {
455                 d_printf("Group %s added\n", argv[0]);
456                 rc = 0;
457         } else {
458                 d_printf("Could not add group %s: %s\n", argv[0],
459                          ads_errstr(status));
460         }
461
462  done:
463         if (res)
464                 ads_msgfree(ads, res);
465         ads_destroy(&ads);
466         return rc;
467 }
468
469 static int ads_group_delete(int argc, const char **argv)
470 {
471         ADS_STRUCT *ads;
472         ADS_STATUS rc;
473         void *res;
474         char *groupdn;
475
476         if (argc < 1) return net_ads_group_usage(argc, argv);
477         
478         if (!(ads = ads_startup())) return -1;
479
480         rc = ads_find_user_acct(ads, &res, argv[0]);
481         if (!ADS_ERR_OK(rc)) {
482                 DEBUG(0, ("Group %s does not exist\n", argv[0]));
483                 return -1;
484         }
485         groupdn = ads_get_dn(ads, res);
486         ads_msgfree(ads, res);
487         rc = ads_del_dn(ads, groupdn);
488         ads_memfree(ads, groupdn);
489         if (!ADS_ERR_OK(rc)) {
490                 d_printf("Group %s deleted\n", argv[0]);
491                 return 0;
492         }
493         d_printf("Error deleting group %s: %s\n", argv[0], 
494                  ads_errstr(rc));
495         return -1;
496 }
497
498 int net_ads_group(int argc, const char **argv)
499 {
500         struct functable func[] = {
501                 {"ADD", ads_group_add},
502                 {"DELETE", ads_group_delete},
503                 {NULL, NULL}
504         };
505         ADS_STRUCT *ads;
506         ADS_STATUS rc;
507         const char *shortattrs[] = {"sAMAccountName", NULL};
508         const char *longattrs[] = {"sAMAccountName", "description", NULL};
509         char *disp_fields[2] = {NULL, NULL};
510
511         if (argc == 0) {
512                 if (!(ads = ads_startup())) return -1;
513
514                 if (opt_long_list_entries)
515                         d_printf("\nGroup name            Comment"\
516                                  "\n-----------------------------\n");
517                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
518                                           LDAP_SCOPE_SUBTREE, 
519                                           "(objectclass=group)", 
520                                           opt_long_list_entries ? longattrs : 
521                                           shortattrs, usergrp_display, 
522                                           disp_fields);
523
524                 ads_destroy(&ads);
525                 return 0;
526         }
527         return net_run_function(argc, argv, func, net_ads_group_usage);
528 }
529
530 static int net_ads_status(int argc, const char **argv)
531 {
532         ADS_STRUCT *ads;
533         ADS_STATUS rc;
534         void *res;
535
536         if (!(ads = ads_startup())) return -1;
537
538         rc = ads_find_machine_acct(ads, &res, global_myname());
539         if (!ADS_ERR_OK(rc)) {
540                 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
541                 return -1;
542         }
543
544         if (ads_count_replies(ads, res) == 0) {
545                 d_printf("No machine account for '%s' found\n", global_myname());
546                 return -1;
547         }
548
549         ads_dump(ads, res);
550
551         return 0;
552 }
553
554 static int net_ads_leave(int argc, const char **argv)
555 {
556         ADS_STRUCT *ads = NULL;
557         ADS_STATUS rc;
558
559         if (!secrets_init()) {
560                 DEBUG(1,("Failed to initialise secrets database\n"));
561                 return -1;
562         }
563
564         if (!opt_password) {
565                 char *user_name;
566                 asprintf(&user_name, "%s$", global_myname());
567                 opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
568                 opt_user_name = user_name;
569         }
570
571         if (!(ads = ads_startup())) {
572                 return -1;
573         }
574
575         rc = ads_leave_realm(ads, global_myname());
576         if (!ADS_ERR_OK(rc)) {
577             d_printf("Failed to delete host '%s' from the '%s' realm.\n", 
578                      global_myname(), ads->config.realm);
579             return -1;
580         }
581
582         d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
583
584         return 0;
585 }
586
587 static int net_ads_join_ok(void)
588 {
589         char *user_name;
590         ADS_STRUCT *ads = NULL;
591
592         if (!secrets_init()) {
593                 DEBUG(1,("Failed to initialise secrets database\n"));
594                 return -1;
595         }
596
597         asprintf(&user_name, "%s$", global_myname());
598         opt_user_name = user_name;
599         opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
600
601         if (!(ads = ads_startup())) {
602                 return -1;
603         }
604
605         ads_destroy(&ads);
606         return 0;
607 }
608
609 /*
610   check that an existing join is OK
611  */
612 int net_ads_testjoin(int argc, const char **argv)
613 {
614         use_in_memory_ccache();
615
616         /* Display success or failure */
617         if (net_ads_join_ok() != 0) {
618                 fprintf(stderr,"Join to domain is not valid\n");
619                 return -1;
620         }
621
622         printf("Join is OK\n");
623         return 0;
624 }
625
626 /*
627   join a domain using ADS
628  */
629 int net_ads_join(int argc, const char **argv)
630 {
631         ADS_STRUCT *ads;
632         ADS_STATUS rc;
633         char *password;
634         char *tmp_password;
635         const char *org_unit = "Computers";
636         char *dn;
637         void *res;
638         DOM_SID dom_sid;
639         char *ou_str;
640         uint32 sec_channel_type = SEC_CHAN_WKSTA;
641         uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
642
643         if (argc > 0) org_unit = argv[0];
644
645         if (!secrets_init()) {
646                 DEBUG(1,("Failed to initialise secrets database\n"));
647                 return -1;
648         }
649
650         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
651         password = strdup(tmp_password);
652
653         if (!(ads = ads_startup())) return -1;
654
655         ou_str = ads_ou_string(org_unit);
656         asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
657         free(ou_str);
658
659         rc = ads_search_dn(ads, &res, dn, NULL);
660         ads_msgfree(ads, res);
661
662         if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
663                 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", 
664                          org_unit, dn);
665                 return -1;
666         }
667         free(dn);
668
669         if (!ADS_ERR_OK(rc)) {
670                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
671                 return -1;
672         }       
673
674         rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
675         if (!ADS_ERR_OK(rc)) {
676                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
677                 return -1;
678         }
679
680         rc = ads_domain_sid(ads, &dom_sid);
681         if (!ADS_ERR_OK(rc)) {
682                 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
683                 return -1;
684         }
685
686         rc = ads_set_machine_password(ads, global_myname(), password);
687         if (!ADS_ERR_OK(rc)) {
688                 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
689                 return -1;
690         }
691
692         if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
693                 DEBUG(1,("Failed to save domain sid\n"));
694                 return -1;
695         }
696
697         if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
698                 DEBUG(1,("Failed to save machine password\n"));
699                 return -1;
700         }
701
702         d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
703
704         free(password);
705
706         return 0;
707 }
708
709 int net_ads_printer_usage(int argc, const char **argv)
710 {
711         d_printf(
712 "\nnet ads printer info <printer> <server>"
713 "\n\tlookup info in directory for printer on server"
714 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
715 "\nnet ads printer publish <printername>"
716 "\n\tpublish printer in directory"
717 "\n\t(note: printer name is required)\n"
718 "\nnet ads printer remove <printername>"
719 "\n\tremove printer from directory"
720 "\n\t(note: printer name is required)\n");
721         return -1;
722 }
723
724 static int net_ads_printer_info(int argc, const char **argv)
725 {
726         ADS_STRUCT *ads;
727         ADS_STATUS rc;
728         const char *servername, *printername;
729         void *res = NULL;
730
731         if (!(ads = ads_startup())) return -1;
732
733         if (argc > 0)
734                 printername = argv[0];
735         else
736                 printername = "*";
737
738         if (argc > 1)
739                 servername =  argv[1];
740         else
741                 servername = global_myname();
742
743         rc = ads_find_printer_on_server(ads, &res, printername, servername);
744
745         if (!ADS_ERR_OK(rc)) {
746                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
747                 ads_msgfree(ads, res);
748                 return -1;
749         }
750
751         if (ads_count_replies(ads, res) == 0) {
752                 d_printf("Printer '%s' not found\n", printername);
753                 ads_msgfree(ads, res);
754                 return -1;
755         }
756
757         ads_dump(ads, res);
758         ads_msgfree(ads, res);
759
760         return 0;
761 }
762
763 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
764 {
765         return;
766 }
767
768 static int net_ads_printer_publish(int argc, const char **argv)
769 {
770         ADS_STRUCT *ads;
771         ADS_STATUS rc;
772         const char *servername;
773         struct cli_state *cli;
774         struct in_addr          server_ip;
775         NTSTATUS nt_status;
776         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
777         ADS_MODLIST mods = ads_init_mods(mem_ctx);
778         char *prt_dn, *srv_dn, **srv_cn;
779         void *res = NULL;
780
781         if (!(ads = ads_startup())) return -1;
782
783         if (argc < 1)
784                 return net_ads_printer_usage(argc, argv);
785         
786         if (argc == 2)
787                 servername = argv[1];
788         else
789                 servername = global_myname();
790                 
791         ads_find_machine_acct(ads, &res, servername);
792         srv_dn = ldap_get_dn(ads->ld, res);
793         srv_cn = ldap_explode_dn(srv_dn, 1);
794         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], argv[0], srv_dn);
795
796         resolve_name(servername, &server_ip, 0x20);
797
798         nt_status = cli_full_connection(&cli, global_myname(), servername, 
799                                         &server_ip, 0,
800                                         "IPC$", "IPC",  
801                                         opt_user_name, opt_workgroup,
802                                         opt_password ? opt_password : "", 
803                                         CLI_FULL_CONNECTION_USE_KERBEROS, 
804                                         NULL);
805
806         cli_nt_session_open(cli, PI_SPOOLSS);
807         get_remote_printer_publishing_data(cli, mem_ctx, &mods, argv[0]);
808
809         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
810         if (!ADS_ERR_OK(rc)) {
811                 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
812                 return -1;
813         }
814  
815         d_printf("published printer\n");
816  
817         return 0;
818 }
819
820 static int net_ads_printer_remove(int argc, const char **argv)
821 {
822         ADS_STRUCT *ads;
823         ADS_STATUS rc;
824         const char *servername;
825         char *prt_dn;
826         void *res = NULL;
827
828         if (!(ads = ads_startup())) return -1;
829
830         if (argc < 1)
831                 return net_ads_printer_usage(argc, argv);
832
833         if (argc > 1)
834                 servername = argv[1];
835         else
836                 servername = global_myname();
837
838         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
839
840         if (!ADS_ERR_OK(rc)) {
841                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
842                 ads_msgfree(ads, res);
843                 return -1;
844         }
845
846         if (ads_count_replies(ads, res) == 0) {
847                 d_printf("Printer '%s' not found\n", argv[1]);
848                 ads_msgfree(ads, res);
849                 return -1;
850         }
851
852         prt_dn = ads_get_dn(ads, res);
853         ads_msgfree(ads, res);
854         rc = ads_del_dn(ads, prt_dn);
855         ads_memfree(ads, prt_dn);
856
857         if (!ADS_ERR_OK(rc)) {
858                 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
859                 return -1;
860         }
861
862         return 0;
863 }
864
865 static int net_ads_printer(int argc, const char **argv)
866 {
867         struct functable func[] = {
868                 {"INFO", net_ads_printer_info},
869                 {"PUBLISH", net_ads_printer_publish},
870                 {"REMOVE", net_ads_printer_remove},
871                 {NULL, NULL}
872         };
873         
874         return net_run_function(argc, argv, func, net_ads_printer_usage);
875 }
876
877
878 static int net_ads_password(int argc, const char **argv)
879 {
880     ADS_STRUCT *ads;
881     const char *auth_principal = opt_user_name;
882     const char *auth_password = opt_password;
883     char *realm = NULL;
884     char *new_password = NULL;
885     char *c;
886     char *prompt;
887     ADS_STATUS ret;
888
889     
890     if ((argc != 1) || (opt_user_name == NULL) || 
891         (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
892         (strchr(argv[0], '@') == NULL)) {
893         return net_ads_usage(argc, argv);
894     }
895
896     use_in_memory_ccache();    
897     c = strchr(auth_principal, '@');
898     realm = ++c;
899
900     /* use the realm so we can eventually change passwords for users 
901     in realms other than default */
902     if (!(ads = ads_init(realm, NULL, NULL))) return -1;
903
904     /* we don't actually need a full connect, but it's the easy way to
905        fill in the KDC's addresss */
906     ads_connect(ads);
907     
908     if (!ads || !ads->config.realm) {
909             d_printf("Didn't find the kerberos server!\n");
910             return -1;
911     }
912
913     asprintf(&prompt, "Enter new password for %s:", argv[0]);
914
915     new_password = getpass(prompt);
916
917     ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
918                                 auth_password, argv[0], new_password, ads->auth.time_offset);
919     if (!ADS_ERR_OK(ret)) {
920         d_printf("Password change failed :-( ...\n");
921         ads_destroy(&ads);
922         free(prompt);
923         return -1;
924     }
925
926     d_printf("Password change for %s completed.\n", argv[0]);
927     ads_destroy(&ads);
928     free(prompt);
929
930     return 0;
931 }
932
933
934 int net_ads_changetrustpw(int argc, const char **argv)
935 {    
936     ADS_STRUCT *ads;
937     char *host_principal;
938     char *hostname;
939     ADS_STATUS ret;
940     char *user_name;
941
942     if (!secrets_init()) {
943             DEBUG(1,("Failed to initialise secrets database\n"));
944             return -1;
945     }
946
947     asprintf(&user_name, "%s$", global_myname());
948     opt_user_name = user_name;
949
950     opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
951
952     use_in_memory_ccache();
953
954     if (!(ads = ads_startup())) {
955             return -1;
956     }
957
958     hostname = strdup(global_myname());
959     strlower(hostname);
960     asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
961     SAFE_FREE(hostname);
962     d_printf("Changing password for principal: HOST/%s\n", host_principal);
963     
964     ret = ads_change_trust_account_password(ads, host_principal);
965
966     if (!ADS_ERR_OK(ret)) {
967         d_printf("Password change failed :-( ...\n");
968         ads_destroy(&ads);
969         SAFE_FREE(host_principal);
970         return -1;
971     }
972     
973     d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
974     ads_destroy(&ads);
975     SAFE_FREE(host_principal);
976
977     return 0;
978 }
979
980 /*
981   help for net ads search
982 */
983 static int net_ads_search_usage(int argc, const char **argv)
984 {
985         d_printf(
986                 "\nnet ads search <expression> <attributes...>\n"\
987                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
988                 "The expression is a standard LDAP search expression, and the\n"\
989                 "attributes are a list of LDAP fields to show in the results\n\n"\
990                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
991                 );
992         net_common_flags_usage(argc, argv);
993         return -1;
994 }
995
996
997 /*
998   general ADS search function. Useful in diagnosing problems in ADS
999 */
1000 static int net_ads_search(int argc, const char **argv)
1001 {
1002         ADS_STRUCT *ads;
1003         ADS_STATUS rc;
1004         const char *exp;
1005         const char **attrs;
1006         void *res = NULL;
1007
1008         if (argc < 1) {
1009                 return net_ads_search_usage(argc, argv);
1010         }
1011
1012         if (!(ads = ads_startup())) {
1013                 return -1;
1014         }
1015
1016         exp = argv[0];
1017         attrs = (argv + 1);
1018
1019         rc = ads_do_search_all(ads, ads->config.bind_path,
1020                                LDAP_SCOPE_SUBTREE,
1021                                exp, attrs, &res);
1022         if (!ADS_ERR_OK(rc)) {
1023                 d_printf("search failed: %s\n", ads_errstr(rc));
1024                 return -1;
1025         }       
1026
1027         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1028
1029         /* dump the results */
1030         ads_dump(ads, res);
1031
1032         ads_msgfree(ads, res);
1033         ads_destroy(&ads);
1034
1035         return 0;
1036 }
1037
1038
1039 /*
1040   help for net ads search
1041 */
1042 static int net_ads_dn_usage(int argc, const char **argv)
1043 {
1044         d_printf(
1045                 "\nnet ads dn <dn> <attributes...>\n"\
1046                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1047                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1048                 "to show in the results\n\n"\
1049                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1050                 );
1051         net_common_flags_usage(argc, argv);
1052         return -1;
1053 }
1054
1055
1056 /*
1057   general ADS search function. Useful in diagnosing problems in ADS
1058 */
1059 static int net_ads_dn(int argc, const char **argv)
1060 {
1061         ADS_STRUCT *ads;
1062         ADS_STATUS rc;
1063         const char *dn;
1064         const char **attrs;
1065         void *res = NULL;
1066
1067         if (argc < 1) {
1068                 return net_ads_dn_usage(argc, argv);
1069         }
1070
1071         if (!(ads = ads_startup())) {
1072                 return -1;
1073         }
1074
1075         dn = argv[0];
1076         attrs = (argv + 1);
1077
1078         rc = ads_do_search_all(ads, dn, 
1079                                LDAP_SCOPE_BASE,
1080                                "(objectclass=*)", attrs, &res);
1081         if (!ADS_ERR_OK(rc)) {
1082                 d_printf("search failed: %s\n", ads_errstr(rc));
1083                 return -1;
1084         }       
1085
1086         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1087
1088         /* dump the results */
1089         ads_dump(ads, res);
1090
1091         ads_msgfree(ads, res);
1092         ads_destroy(&ads);
1093
1094         return 0;
1095 }
1096
1097
1098 int net_ads_help(int argc, const char **argv)
1099 {
1100         struct functable func[] = {
1101                 {"USER", net_ads_user_usage},
1102                 {"GROUP", net_ads_group_usage},
1103                 {"PRINTER", net_ads_printer_usage},
1104                 {"SEARCH", net_ads_search_usage},
1105 #if 0
1106                 {"INFO", net_ads_info},
1107                 {"JOIN", net_ads_join},
1108                 {"LEAVE", net_ads_leave},
1109                 {"STATUS", net_ads_status},
1110                 {"PASSWORD", net_ads_password},
1111                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1112 #endif
1113                 {NULL, NULL}
1114         };
1115
1116         return net_run_function(argc, argv, func, net_ads_usage);
1117 }
1118
1119 int net_ads(int argc, const char **argv)
1120 {
1121         struct functable func[] = {
1122                 {"INFO", net_ads_info},
1123                 {"JOIN", net_ads_join},
1124                 {"TESTJOIN", net_ads_testjoin},
1125                 {"LEAVE", net_ads_leave},
1126                 {"STATUS", net_ads_status},
1127                 {"USER", net_ads_user},
1128                 {"GROUP", net_ads_group},
1129                 {"PASSWORD", net_ads_password},
1130                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1131                 {"PRINTER", net_ads_printer},
1132                 {"SEARCH", net_ads_search},
1133                 {"DN", net_ads_dn},
1134                 {"WORKGROUP", net_ads_workgroup},
1135                 {"LOOKUP", net_ads_lookup},
1136                 {"HELP", net_ads_help},
1137                 {NULL, NULL}
1138         };
1139         
1140         return net_run_function(argc, argv, func, net_ads_usage);
1141 }
1142
1143 #else
1144
1145 static int net_ads_noads(void)
1146 {
1147         d_printf("ADS support not compiled in\n");
1148         return -1;
1149 }
1150
1151 int net_ads_usage(int argc, const char **argv)
1152 {
1153         return net_ads_noads();
1154 }
1155
1156 int net_ads_help(int argc, const char **argv)
1157 {
1158         return net_ads_noads();
1159 }
1160
1161 int net_ads_changetrustpw(int argc, const char **argv)
1162 {
1163         return net_ads_noads();
1164 }
1165
1166 int net_ads_join(int argc, const char **argv)
1167 {
1168         return net_ads_noads();
1169 }
1170
1171 int net_ads_user(int argc, const char **argv)
1172 {
1173         return net_ads_noads();
1174 }
1175
1176 int net_ads_group(int argc, const char **argv)
1177 {
1178         return net_ads_noads();
1179 }
1180
1181 /* this one shouldn't display a message */
1182 int net_ads_check(void)
1183 {
1184         return -1;
1185 }
1186
1187 int net_ads(int argc, const char **argv)
1188 {
1189         return net_ads_usage(argc, argv);
1190 }
1191
1192 #endif