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