This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[sfrench/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
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 password <username@realm> -Uadmin_username@realm%%admin_pass"\
46 "\n\tchange a user's password using an admin account"\
47 "\n\t(note: use realm in UPPERCASE)\n"\
48 "\nnet ads chostpass"\
49 "\n\tchange the trust account password of this machine in the AD tree\n"\
50 "\nnet ads printer [info | publish | remove] <printername> <servername>"\
51 "\n\t lookup, add, or remove directory entry for a printer\n"\
52 "\nnet ads search"\
53 "\n\tperform a raw LDAP search and dump the results\n"
54                 );
55         return -1;
56 }
57
58
59 static int net_ads_info(int argc, const char **argv)
60 {
61         ADS_STRUCT *ads;
62
63         ads = ads_init(NULL, NULL, opt_host);
64
65         if (ads) {
66                 ads->auth.no_bind = 1;
67         }
68
69         ads_connect(ads);
70
71         if (!ads || !ads->config.realm) {
72                 d_printf("Didn't find the ldap server!\n");
73                 return -1;
74         }
75
76         d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
77         d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
78         d_printf("Realm: %s\n", ads->config.realm);
79         d_printf("Bind Path: %s\n", ads->config.bind_path);
80         d_printf("LDAP port: %d\n", ads->ldap_port);
81
82         return 0;
83 }
84
85
86 static ADS_STRUCT *ads_startup(void)
87 {
88         ADS_STRUCT *ads;
89         ADS_STATUS status;
90         BOOL need_password = False;
91         BOOL second_time = False;
92         
93         ads = ads_init(NULL, NULL, opt_host);
94
95         if (!opt_user_name) {
96                 opt_user_name = "administrator";
97         }
98
99         if (opt_user_specified)
100                 need_password = True;
101
102 retry:
103         if (!opt_password && need_password) {
104                 char *prompt;
105                 asprintf(&prompt,"%s password: ", opt_user_name);
106                 opt_password = getpass(prompt);
107                 free(prompt);
108         }
109
110         if (opt_password)
111                 ads->auth.password = strdup(opt_password);
112
113         ads->auth.user_name = strdup(opt_user_name);
114
115         status = ads_connect(ads);
116         if (!ADS_ERR_OK(status)) {
117                 if (!need_password && !second_time) {
118                         need_password = True;
119                         second_time = True;
120                         goto retry;
121                 } else {
122                         DEBUG(1,("ads_connect: %s\n", ads_errstr(status)));
123                         return NULL;
124                 }
125         }
126         return ads;
127 }
128
129
130 /*
131   Check to see if connection can be made via ads.
132   ads_startup() stores the password in opt_password if it needs to so
133   that rpc or rap can use it without re-prompting.
134 */
135 int net_ads_check(void)
136 {
137         ADS_STRUCT *ads;
138
139         ads = ads_startup();
140         if (!ads)
141                 return -1;
142         ads_destroy(&ads);
143         return 0;
144 }
145
146 /* 
147    determine the netbios workgroup name for a domain
148  */
149 static int net_ads_workgroup(int argc, const char **argv)
150 {
151         ADS_STRUCT *ads;
152         TALLOC_CTX *ctx;
153         char *workgroup;
154
155         if (!(ads = ads_startup())) return -1;
156
157         if (!(ctx = talloc_init_named("net_ads_workgroup"))) {
158                 return -1;
159         }
160
161         if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
162                 d_printf("Failed to find workgroup for realm '%s'\n", 
163                          ads->config.realm);
164                 talloc_destroy(ctx);
165                 return -1;
166         }
167
168         d_printf("Workgroup: %s\n", workgroup);
169
170         talloc_destroy(ctx);
171
172         return 0;
173 }
174
175
176
177 static void usergrp_display(char *field, void **values, void *data_area)
178 {
179         char **disp_fields = (char **) data_area;
180
181         if (!field) { /* must be end of record */
182                 if (!strchr_m(disp_fields[0], '$')) {
183                         if (disp_fields[1])
184                                 d_printf("%-21.21s %-50.50s\n", 
185                                        disp_fields[0], disp_fields[1]);
186                         else
187                                 d_printf("%s\n", disp_fields[0]);
188                 }
189                 SAFE_FREE(disp_fields[0]);
190                 SAFE_FREE(disp_fields[1]);
191                 return;
192         }
193         if (!values) /* must be new field, indicate string field */
194                 return;
195         if (StrCaseCmp(field, "sAMAccountName") == 0) {
196                 disp_fields[0] = strdup((char *) values[0]);
197         }
198         if (StrCaseCmp(field, "description") == 0)
199                 disp_fields[1] = strdup((char *) values[0]);
200 }
201
202 static int net_ads_user_usage(int argc, const char **argv)
203 {
204         return net_help_user(argc, argv);
205
206
207 static int ads_user_add(int argc, const char **argv)
208 {
209         ADS_STRUCT *ads;
210         ADS_STATUS status;
211         char *upn, *userdn;
212         void *res=NULL;
213         int rc = -1;
214
215         if (argc < 1) return net_ads_user_usage(argc, argv);
216         
217         if (!(ads = ads_startup())) return -1;
218
219         status = ads_find_user_acct(ads, &res, argv[0]);
220
221         if (!ADS_ERR_OK(status)) {
222                 d_printf("ads_user_add: %s\n", ads_errstr(status));
223                 goto done;
224         }
225         
226         if (ads_count_replies(ads, res)) {
227                 d_printf("ads_user_add: User %s already exists\n", argv[0]);
228                 goto done;
229         }
230
231         status = ads_add_user_acct(ads, argv[0], opt_comment);
232
233         if (!ADS_ERR_OK(status)) {
234                 d_printf("Could not add user %s: %s\n", argv[0],
235                          ads_errstr(status));
236                 goto done;
237         }
238
239         /* if no password is to be set, we're done */
240         if (argc == 1) { 
241                 d_printf("User %s added\n", argv[0]);
242                 rc = 0;
243                 goto done;
244         }
245
246         /* try setting the password */
247         asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
248         status = krb5_set_password(ads->auth.kdc_server, upn, argv[1]);
249         safe_free(upn);
250         if (ADS_ERR_OK(status)) {
251                 d_printf("User %s added\n", argv[0]);
252                 rc = 0;
253                 goto done;
254         }
255
256         /* password didn't set, delete account */
257         d_printf("Could not add user %s.  Error setting password %s\n",
258                  argv[0], ads_errstr(status));
259         ads_msgfree(ads, res);
260         status=ads_find_user_acct(ads, &res, argv[0]);
261         if (ADS_ERR_OK(status)) {
262                 userdn = ads_get_dn(ads, res);
263                 ads_del_dn(ads, userdn);
264                 ads_memfree(ads, userdn);
265         }
266
267  done:
268         if (res)
269                 ads_msgfree(ads, res);
270         ads_destroy(&ads);
271         return rc;
272 }
273
274 static int ads_user_info(int argc, const char **argv)
275 {
276         ADS_STRUCT *ads;
277         ADS_STATUS rc;
278         void *res;
279         const char *attrs[] = {"memberOf", NULL};
280         char *searchstring=NULL;
281         char **grouplist;
282
283         if (argc < 1) return net_ads_user_usage(argc, argv);
284         
285         if (!(ads = ads_startup())) return -1;
286
287         asprintf(&searchstring, "(sAMAccountName=%s)", argv[0]);
288         rc = ads_search(ads, &res, searchstring, attrs);
289         safe_free(searchstring);
290
291         if (!ADS_ERR_OK(rc)) {
292                 d_printf("ads_search: %s\n", ads_errstr(rc));
293                 return -1;
294         }
295         
296         grouplist = ldap_get_values(ads->ld, res, "memberOf");
297
298         if (grouplist) {
299                 int i;
300                 char **groupname;
301                 for (i=0;grouplist[i];i++) {
302                         groupname = ldap_explode_dn(grouplist[i], 1);
303                         d_printf("%s\n", groupname[0]);
304                         ldap_value_free(groupname);
305                 }
306                 ldap_value_free(grouplist);
307         }
308         
309         ads_msgfree(ads, res);
310
311         ads_destroy(&ads);
312         return 0;
313 }
314
315 static int ads_user_delete(int argc, const char **argv)
316 {
317         ADS_STRUCT *ads;
318         ADS_STATUS rc;
319         void *res;
320         char *userdn;
321
322         if (argc < 1) return net_ads_user_usage(argc, argv);
323         
324         if (!(ads = ads_startup())) return -1;
325
326         rc = ads_find_user_acct(ads, &res, argv[0]);
327         if (!ADS_ERR_OK(rc)) {
328                 DEBUG(0, ("User %s does not exist\n", argv[0]));
329                 return -1;
330         }
331         userdn = ads_get_dn(ads, res);
332         ads_msgfree(ads, res);
333         rc = ads_del_dn(ads, userdn);
334         ads_memfree(ads, userdn);
335         if (!ADS_ERR_OK(rc)) {
336                 d_printf("User %s deleted\n", argv[0]);
337                 return 0;
338         }
339         d_printf("Error deleting user %s: %s\n", argv[0], 
340                  ads_errstr(rc));
341         return -1;
342 }
343
344 int net_ads_user(int argc, const char **argv)
345 {
346         struct functable func[] = {
347                 {"ADD", ads_user_add},
348                 {"INFO", ads_user_info},
349                 {"DELETE", ads_user_delete},
350                 {NULL, NULL}
351         };
352         ADS_STRUCT *ads;
353         ADS_STATUS rc;
354         const char *shortattrs[] = {"sAMAccountName", NULL};
355         const char *longattrs[] = {"sAMAccountName", "description", NULL};
356         char *disp_fields[2] = {NULL, NULL};
357         
358         if (argc == 0) {
359                 if (!(ads = ads_startup())) return -1;
360
361                 if (opt_long_list_entries)
362                         d_printf("\nUser name             Comment"\
363                                  "\n-----------------------------\n");
364
365                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
366                                           LDAP_SCOPE_SUBTREE,
367                                           "(objectclass=user)", 
368                                           opt_long_list_entries ? longattrs :
369                                           shortattrs, usergrp_display, 
370                                           disp_fields);
371                 ads_destroy(&ads);
372                 return 0;
373         }
374
375         return net_run_function(argc, argv, func, net_ads_user_usage);
376 }
377
378 static int net_ads_group_usage(int argc, const char **argv)
379 {
380         return net_help_group(argc, argv);
381
382
383 static int ads_group_add(int argc, const char **argv)
384 {
385         ADS_STRUCT *ads;
386         ADS_STATUS status;
387         void *res=NULL;
388         int rc = -1;
389
390         if (argc < 1) return net_ads_group_usage(argc, argv);
391         
392         if (!(ads = ads_startup())) return -1;
393
394         status = ads_find_user_acct(ads, &res, argv[0]);
395
396         if (!ADS_ERR_OK(status)) {
397                 d_printf("ads_group_add: %s\n", ads_errstr(status));
398                 goto done;
399         }
400         
401         if (ads_count_replies(ads, res)) {
402                 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
403                 ads_msgfree(ads, res);
404                 goto done;
405         }
406
407         status = ads_add_group_acct(ads, argv[0], opt_comment);
408
409         if (ADS_ERR_OK(status)) {
410                 d_printf("Group %s added\n", argv[0]);
411                 rc = 0;
412         } else {
413                 d_printf("Could not add group %s: %s\n", argv[0],
414                          ads_errstr(status));
415         }
416
417  done:
418         if (res)
419                 ads_msgfree(ads, res);
420         ads_destroy(&ads);
421         return rc;
422 }
423
424 static int ads_group_delete(int argc, const char **argv)
425 {
426         ADS_STRUCT *ads;
427         ADS_STATUS rc;
428         void *res;
429         char *groupdn;
430
431         if (argc < 1) return net_ads_group_usage(argc, argv);
432         
433         if (!(ads = ads_startup())) return -1;
434
435         rc = ads_find_user_acct(ads, &res, argv[0]);
436         if (!ADS_ERR_OK(rc)) {
437                 DEBUG(0, ("Group %s does not exist\n", argv[0]));
438                 return -1;
439         }
440         groupdn = ads_get_dn(ads, res);
441         ads_msgfree(ads, res);
442         rc = ads_del_dn(ads, groupdn);
443         ads_memfree(ads, groupdn);
444         if (!ADS_ERR_OK(rc)) {
445                 d_printf("Group %s deleted\n", argv[0]);
446                 return 0;
447         }
448         d_printf("Error deleting group %s: %s\n", argv[0], 
449                  ads_errstr(rc));
450         return -1;
451 }
452
453 int net_ads_group(int argc, const char **argv)
454 {
455         struct functable func[] = {
456                 {"ADD", ads_group_add},
457                 {"DELETE", ads_group_delete},
458                 {NULL, NULL}
459         };
460         ADS_STRUCT *ads;
461         ADS_STATUS rc;
462         const char *shortattrs[] = {"sAMAccountName", NULL};
463         const char *longattrs[] = {"sAMAccountName", "description", NULL};
464         char *disp_fields[2] = {NULL, NULL};
465
466         if (argc == 0) {
467                 if (!(ads = ads_startup())) return -1;
468
469                 if (opt_long_list_entries)
470                         d_printf("\nGroup name            Comment"\
471                                  "\n-----------------------------\n");
472                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
473                                           LDAP_SCOPE_SUBTREE, 
474                                           "(objectclass=group)", 
475                                           opt_long_list_entries ? longattrs : 
476                                           shortattrs, usergrp_display, 
477                                           disp_fields);
478
479                 ads_destroy(&ads);
480                 return 0;
481         }
482         return net_run_function(argc, argv, func, net_ads_group_usage);
483 }
484
485 static int net_ads_status(int argc, const char **argv)
486 {
487         ADS_STRUCT *ads;
488         ADS_STATUS rc;
489         extern pstring global_myname;
490         void *res;
491
492         if (!(ads = ads_startup())) return -1;
493
494         rc = ads_find_machine_acct(ads, &res, global_myname);
495         if (!ADS_ERR_OK(rc)) {
496                 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
497                 return -1;
498         }
499
500         if (ads_count_replies(ads, res) == 0) {
501                 d_printf("No machine account for '%s' found\n", global_myname);
502                 return -1;
503         }
504
505         ads_dump(ads, res);
506
507         return 0;
508 }
509
510 static int net_ads_leave(int argc, const char **argv)
511 {
512         ADS_STRUCT *ads = NULL;
513         ADS_STATUS rc;
514         extern pstring global_myname;
515
516         if (!secrets_init()) {
517                 DEBUG(1,("Failed to initialise secrets database\n"));
518                 return -1;
519         }
520
521         if (!opt_password) {
522                 asprintf(&opt_user_name, "%s$", global_myname);
523                 opt_password = secrets_fetch_machine_password();
524         }
525
526         if (!(ads = ads_startup())) {
527                 return -1;
528         }
529
530         rc = ads_leave_realm(ads, global_myname);
531         if (!ADS_ERR_OK(rc)) {
532             d_printf("Failed to delete host '%s' from the '%s' realm.\n", 
533                      global_myname, ads->config.realm);
534             return -1;
535         }
536
537         d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->config.realm);
538
539         return 0;
540 }
541
542 static int net_ads_join_ok(void)
543 {
544         ADS_STRUCT *ads = NULL;
545         extern pstring global_myname;
546
547         if (!secrets_init()) {
548                 DEBUG(1,("Failed to initialise secrets database\n"));
549                 return -1;
550         }
551
552         asprintf(&opt_user_name, "%s$", global_myname);
553         opt_password = secrets_fetch_machine_password();
554
555         if (!(ads = ads_startup())) {
556                 return -1;
557         }
558
559         ads_destroy(&ads);
560         return 0;
561 }
562
563 /*
564   check that an existing join is OK
565  */
566 int net_ads_testjoin(int argc, const char **argv)
567 {
568         /* Display success or failure */
569         if (net_ads_join_ok() != 0) {
570                 fprintf(stderr,"Join to domain is not valid\n");
571                 return -1;
572         }
573
574         printf("Join is OK\n");
575         return 0;
576 }
577
578 /*
579   join a domain using ADS
580  */
581 int net_ads_join(int argc, const char **argv)
582 {
583         ADS_STRUCT *ads;
584         ADS_STATUS rc;
585         char *password;
586         char *tmp_password;
587         extern pstring global_myname;
588         const char *org_unit = "Computers";
589         char *dn;
590         void *res;
591         DOM_SID dom_sid;
592         char *ou_str;
593
594         if (argc > 0) org_unit = argv[0];
595
596         if (!secrets_init()) {
597                 DEBUG(1,("Failed to initialise secrets database\n"));
598                 return -1;
599         }
600
601         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
602         password = strdup(tmp_password);
603
604         if (!(ads = ads_startup())) return -1;
605
606         ou_str = ads_ou_string(org_unit);
607         asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
608         free(ou_str);
609
610         rc = ads_search_dn(ads, &res, dn, NULL);
611         ads_msgfree(ads, res);
612
613         if (rc.error_type == ADS_ERROR_LDAP && rc.rc == LDAP_NO_SUCH_OBJECT) {
614                 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", 
615                          org_unit, dn);
616                 return -1;
617         }
618         free(dn);
619
620         if (!ADS_ERR_OK(rc)) {
621                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
622                 return -1;
623         }       
624
625         rc = ads_join_realm(ads, global_myname, org_unit);
626         if (!ADS_ERR_OK(rc)) {
627                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
628                 return -1;
629         }
630
631         rc = ads_set_machine_password(ads, global_myname, password);
632         if (!ADS_ERR_OK(rc)) {
633                 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
634                 return -1;
635         }
636
637         rc = ads_domain_sid(ads, &dom_sid);
638         if (!ADS_ERR_OK(rc)) {
639                 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
640                 return -1;
641         }
642
643         if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
644                 DEBUG(1,("Failed to save domain sid\n"));
645                 return -1;
646         }
647
648         if (!secrets_store_machine_password(password)) {
649                 DEBUG(1,("Failed to save machine password\n"));
650                 return -1;
651         }
652
653         d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->config.realm);
654
655         free(password);
656
657         return 0;
658 }
659
660 int net_ads_printer_usage(int argc, const char **argv)
661 {
662         d_printf(
663 "\nnet ads printer info <printer> <server>"
664 "\n\tlookup info in directory for printer on server"
665 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
666 "\nnet ads printer publish <printername>"
667 "\n\tpublish printer in directory"
668 "\n\t(note: printer name is required)\n"
669 "\nnet ads printer remove <printername>"
670 "\n\tremove printer from directory"
671 "\n\t(note: printer name is required)\n");
672         return -1;
673 }
674
675 static int net_ads_printer_info(int argc, const char **argv)
676 {
677         ADS_STRUCT *ads;
678         ADS_STATUS rc;
679         const char *servername, *printername;
680         extern pstring global_myname;
681         void *res = NULL;
682
683         if (!(ads = ads_startup())) return -1;
684
685         if (argc > 0)
686                 printername = argv[0];
687         else
688                 printername = "*";
689
690         if (argc > 1)
691                 servername =  argv[1];
692         else
693                 servername = global_myname;
694
695         rc = ads_find_printer_on_server(ads, &res, printername, servername);
696
697         if (!ADS_ERR_OK(rc)) {
698                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
699                 ads_msgfree(ads, res);
700                 return -1;
701         }
702
703         if (ads_count_replies(ads, res) == 0) {
704                 d_printf("Printer '%s' not found\n", printername);
705                 ads_msgfree(ads, res);
706                 return -1;
707         }
708
709         ads_dump(ads, res);
710         ads_msgfree(ads, res);
711
712         return 0;
713 }
714
715 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
716 {
717         return;
718 }
719
720 static int net_ads_printer_publish(int argc, const char **argv)
721 {
722         ADS_STRUCT *ads;
723         ADS_STATUS rc;
724         char *uncname, *servername;
725         ADS_PRINTER_ENTRY prt;
726         extern pstring global_myname;
727         char *ports[2] = {"Samba", NULL};
728
729         /* 
730            these const strings are only here as an example.  The attributes
731            they represent are not implemented yet
732         */
733         const char *bins[] = {"Tray 21", NULL};
734         const char *media[] = {"Letter", NULL};
735         const char *orients[] = {"PORTRAIT", NULL};
736
737         if (!(ads = ads_startup())) return -1;
738
739         if (argc < 1)
740                 return net_ads_printer_usage(argc, argv);
741
742         memset(&prt, 0, sizeof(ADS_PRINTER_ENTRY));
743
744         /* we don't sue the servername or unc name provided by 
745            get_a_printer, because the server name might be
746            localhost or an ip address */
747         prt.printerName = argv[0];
748         asprintf(&servername, "%s.%s", global_myname, ads->config.realm);
749         prt.serverName = servername;
750         prt.shortServerName = global_myname;
751         prt.versionNumber = "4";
752         asprintf(&uncname, "\\\\%s\\%s", global_myname, argv[0]);
753         prt.uNCName=uncname;
754         prt.printBinNames = (char **) bins;
755         prt.printMediaSupported = (char **) media;
756         prt.printOrientationsSupported = (char **) orients;
757         prt.portName = (char **) ports;
758         prt.printSpooling = "PrintAfterSpooled";
759
760         rc = ads_add_printer(ads, &prt);
761         if (!ADS_ERR_OK(rc)) {
762                 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
763                 return -1;
764         }
765  
766         d_printf("published printer\n");
767  
768         return 0;
769 }
770
771 static int net_ads_printer_remove(int argc, const char **argv)
772 {
773         ADS_STRUCT *ads;
774         ADS_STATUS rc;
775         char *servername, *prt_dn;
776         extern pstring global_myname;
777         void *res = NULL;
778
779         if (!(ads = ads_startup())) return -1;
780
781         if (argc < 1)
782                 return net_ads_printer_usage(argc, argv);
783
784         if (argc > 1)
785                 servername = argv[1];
786         else
787                 servername = global_myname;
788
789         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
790
791         if (!ADS_ERR_OK(rc)) {
792                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
793                 ads_msgfree(ads, res);
794                 return -1;
795         }
796
797         if (ads_count_replies(ads, res) == 0) {
798                 d_printf("Printer '%s' not found\n", argv[1]);
799                 ads_msgfree(ads, res);
800                 return -1;
801         }
802
803         prt_dn = ads_get_dn(ads, res);
804         ads_msgfree(ads, res);
805         rc = ads_del_dn(ads, prt_dn);
806         ads_memfree(ads, prt_dn);
807
808         if (!ADS_ERR_OK(rc)) {
809                 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
810                 return -1;
811         }
812
813         return 0;
814 }
815
816 static int net_ads_printer(int argc, const char **argv)
817 {
818         struct functable func[] = {
819                 {"INFO", net_ads_printer_info},
820                 {"PUBLISH", net_ads_printer_publish},
821                 {"REMOVE", net_ads_printer_remove},
822                 {NULL, NULL}
823         };
824         
825         return net_run_function(argc, argv, func, net_ads_printer_usage);
826 }
827
828
829 static int net_ads_password(int argc, const char **argv)
830 {
831     ADS_STRUCT *ads;
832     char *auth_principal = opt_user_name;
833     char *auth_password = opt_password;
834     char *realm = NULL;
835     char *new_password = NULL;
836     char *c;
837     char *prompt;
838     ADS_STATUS ret;
839
840     
841     if ((argc != 1) || (opt_user_name == NULL) || 
842         (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
843         (strchr(argv[0], '@') == NULL)) {
844         return net_ads_usage(argc, argv);
845     }
846     
847     c = strchr(auth_principal, '@');
848     realm = ++c;
849
850     /* use the realm so we can eventually change passwords for users 
851     in realms other than default */
852     if (!(ads = ads_init(realm, NULL, NULL))) return -1;
853
854     asprintf(&prompt, "Enter new password for %s:", argv[0]);
855
856     new_password = getpass(prompt);
857
858     ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
859                                 auth_password, argv[0], new_password);
860     if (!ADS_ERR_OK(ret)) {
861         d_printf("Password change failed :-( ...\n");
862         ads_destroy(&ads);
863         free(prompt);
864         return -1;
865     }
866
867     d_printf("Password change for %s completed.\n", argv[0]);
868     ads_destroy(&ads);
869     free(prompt);
870
871     return 0;
872 }
873
874
875 static int net_ads_change_localhost_pass(int argc, const char **argv)
876 {    
877     ADS_STRUCT *ads;
878     extern pstring global_myname;
879     char *host_principal;
880     char *hostname;
881     ADS_STATUS ret;
882
883     if (!secrets_init()) {
884             DEBUG(1,("Failed to initialise secrets database\n"));
885             return -1;
886     }
887
888     asprintf(&opt_user_name, "%s$", global_myname);
889     opt_password = secrets_fetch_machine_password();
890
891     if (!(ads = ads_startup())) {
892             return -1;
893     }
894
895     hostname = strdup(global_myname);
896     strlower(hostname);
897     asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
898     SAFE_FREE(hostname);
899     d_printf("Changing password for principal: HOST/%s\n", host_principal);
900     
901     ret = ads_change_trust_account_password(ads, host_principal);
902
903     if (!ADS_ERR_OK(ret)) {
904         d_printf("Password change failed :-( ...\n");
905         ads_destroy(&ads);
906         SAFE_FREE(host_principal);
907         return -1;
908     }
909     
910     d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
911     ads_destroy(&ads);
912     SAFE_FREE(host_principal);
913
914     return 0;
915 }
916
917 /*
918   help for net ads search
919 */
920 static int net_ads_search_usage(int argc, const char **argv)
921 {
922         d_printf(
923                 "\nnet ads search <expression> <attributes...>\n"\
924                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
925                 "The expression is a standard LDAP search expression, and the\n"\
926                 "attributes are a list of LDAP fields to show in the results\n\n"\
927                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
928                 );
929         net_common_flags_usage(argc, argv);
930         return -1;
931 }
932
933
934 /*
935   general ADS search function. Useful in diagnosing problems in ADS
936 */
937 static int net_ads_search(int argc, const char **argv)
938 {
939         ADS_STRUCT *ads;
940         ADS_STATUS rc;
941         const char *exp;
942         const char **attrs;
943         void *res = NULL;
944
945         if (argc < 1) {
946                 return net_ads_search_usage(argc, argv);
947         }
948
949         if (!(ads = ads_startup())) {
950                 return -1;
951         }
952
953         exp = argv[0];
954         attrs = (argv + 1);
955
956         rc = ads_do_search_all(ads, ads->config.bind_path, 
957                                LDAP_SCOPE_SUBTREE,
958                                exp, attrs, &res);
959         if (!ADS_ERR_OK(rc)) {
960                 d_printf("search failed: %s\n", ads_errstr(rc));
961                 return -1;
962         }       
963
964         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
965
966         /* dump the results */
967         ads_dump(ads, res);
968
969         ads_msgfree(ads, res);
970         ads_destroy(&ads);
971
972         return 0;
973 }
974
975
976 int net_ads_help(int argc, const char **argv)
977 {
978         struct functable func[] = {
979                 {"USER", net_ads_user_usage},
980                 {"GROUP", net_ads_group_usage},
981                 {"PRINTER", net_ads_printer_usage},
982                 {"SEARCH", net_ads_search_usage},
983 #if 0
984                 {"INFO", net_ads_info},
985                 {"JOIN", net_ads_join},
986                 {"LEAVE", net_ads_leave},
987                 {"STATUS", net_ads_status},
988                 {"PASSWORD", net_ads_password},
989                 {"CHOSTPASS", net_ads_change_localhost_pass},
990 #endif
991                 {NULL, NULL}
992         };
993
994         return net_run_function(argc, argv, func, net_ads_usage);
995 }
996
997 int net_ads(int argc, const char **argv)
998 {
999         struct functable func[] = {
1000                 {"INFO", net_ads_info},
1001                 {"JOIN", net_ads_join},
1002                 {"TESTJOIN", net_ads_testjoin},
1003                 {"LEAVE", net_ads_leave},
1004                 {"STATUS", net_ads_status},
1005                 {"USER", net_ads_user},
1006                 {"GROUP", net_ads_group},
1007                 {"PASSWORD", net_ads_password},
1008                 {"CHOSTPASS", net_ads_change_localhost_pass},
1009                 {"PRINTER", net_ads_printer},
1010                 {"SEARCH", net_ads_search},
1011                 {"WORKGROUP", net_ads_workgroup},
1012                 {"HELP", net_ads_help},
1013                 {NULL, NULL}
1014         };
1015         
1016         return net_run_function(argc, argv, func, net_ads_usage);
1017 }
1018
1019 #else
1020
1021 static int net_ads_noads(void)
1022 {
1023         d_printf("ADS support not compiled in\n");
1024         return -1;
1025 }
1026
1027 int net_ads_usage(int argc, const char **argv)
1028 {
1029         return net_ads_noads();
1030 }
1031
1032 int net_ads_help(int argc, const char **argv)
1033 {
1034         return net_ads_noads();
1035 }
1036
1037 int net_ads_join(int argc, const char **argv)
1038 {
1039         return net_ads_noads();
1040 }
1041
1042 int net_ads_user(int argc, const char **argv)
1043 {
1044         return net_ads_noads();
1045 }
1046
1047 int net_ads_group(int argc, const char **argv)
1048 {
1049         return net_ads_noads();
1050 }
1051
1052 /* this one shouldn't display a message */
1053 int net_ads_check(void)
1054 {
1055         return -1;
1056 }
1057
1058 int net_ads(int argc, const char **argv)
1059 {
1060         return net_ads_usage(argc, argv);
1061 }
1062
1063 #endif