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