Removed global_myworkgroup, global_myname, global_myscope. Added liberal
[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         void *res;
517
518         if (!(ads = ads_startup())) return -1;
519
520         rc = ads_find_machine_acct(ads, &res, global_myname());
521         if (!ADS_ERR_OK(rc)) {
522                 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
523                 return -1;
524         }
525
526         if (ads_count_replies(ads, res) == 0) {
527                 d_printf("No machine account for '%s' found\n", global_myname());
528                 return -1;
529         }
530
531         ads_dump(ads, res);
532
533         return 0;
534 }
535
536 static int net_ads_leave(int argc, const char **argv)
537 {
538         ADS_STRUCT *ads = NULL;
539         ADS_STATUS rc;
540
541         if (!secrets_init()) {
542                 DEBUG(1,("Failed to initialise secrets database\n"));
543                 return -1;
544         }
545
546         if (!opt_password) {
547                 asprintf(&opt_user_name, "%s$", global_myname());
548                 opt_password = secrets_fetch_machine_password();
549         }
550
551         if (!(ads = ads_startup())) {
552                 return -1;
553         }
554
555         rc = ads_leave_realm(ads, global_myname());
556         if (!ADS_ERR_OK(rc)) {
557             d_printf("Failed to delete host '%s' from the '%s' realm.\n", 
558                      global_myname(), ads->config.realm);
559             return -1;
560         }
561
562         d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
563
564         return 0;
565 }
566
567 static int net_ads_join_ok(void)
568 {
569         ADS_STRUCT *ads = NULL;
570
571         if (!secrets_init()) {
572                 DEBUG(1,("Failed to initialise secrets database\n"));
573                 return -1;
574         }
575
576         asprintf(&opt_user_name, "%s$", global_myname());
577         opt_password = secrets_fetch_machine_password();
578
579         if (!(ads = ads_startup())) {
580                 return -1;
581         }
582
583         ads_destroy(&ads);
584         return 0;
585 }
586
587 /*
588   check that an existing join is OK
589  */
590 int net_ads_testjoin(int argc, const char **argv)
591 {
592         /* Display success or failure */
593         if (net_ads_join_ok() != 0) {
594                 fprintf(stderr,"Join to domain is not valid\n");
595                 return -1;
596         }
597
598         printf("Join is OK\n");
599         return 0;
600 }
601
602 /*
603   join a domain using ADS
604  */
605 int net_ads_join(int argc, const char **argv)
606 {
607         ADS_STRUCT *ads;
608         ADS_STATUS rc;
609         char *password;
610         char *tmp_password;
611         const char *org_unit = "Computers";
612         char *dn;
613         void *res;
614         DOM_SID dom_sid;
615         char *ou_str;
616
617         if (argc > 0) org_unit = argv[0];
618
619         if (!secrets_init()) {
620                 DEBUG(1,("Failed to initialise secrets database\n"));
621                 return -1;
622         }
623
624         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
625         password = strdup(tmp_password);
626
627         if (!(ads = ads_startup())) return -1;
628
629         ou_str = ads_ou_string(org_unit);
630         asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
631         free(ou_str);
632
633         rc = ads_search_dn(ads, &res, dn, NULL);
634         ads_msgfree(ads, res);
635
636         if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
637                 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", 
638                          org_unit, dn);
639                 return -1;
640         }
641         free(dn);
642
643         if (!ADS_ERR_OK(rc)) {
644                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
645                 return -1;
646         }       
647
648         rc = ads_join_realm(ads, global_myname(), org_unit);
649         if (!ADS_ERR_OK(rc)) {
650                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
651                 return -1;
652         }
653
654         rc = ads_domain_sid(ads, &dom_sid);
655         if (!ADS_ERR_OK(rc)) {
656                 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
657                 return -1;
658         }
659
660         rc = ads_set_machine_password(ads, global_myname(), password);
661         if (!ADS_ERR_OK(rc)) {
662                 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
663                 return -1;
664         }
665
666         if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
667                 DEBUG(1,("Failed to save domain sid\n"));
668                 return -1;
669         }
670
671         if (!secrets_store_machine_password(password)) {
672                 DEBUG(1,("Failed to save machine password\n"));
673                 return -1;
674         }
675
676         d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
677
678         free(password);
679
680         return 0;
681 }
682
683 int net_ads_printer_usage(int argc, const char **argv)
684 {
685         d_printf(
686 "\nnet ads printer info <printer> <server>"
687 "\n\tlookup info in directory for printer on server"
688 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
689 "\nnet ads printer publish <printername>"
690 "\n\tpublish printer in directory"
691 "\n\t(note: printer name is required)\n"
692 "\nnet ads printer remove <printername>"
693 "\n\tremove printer from directory"
694 "\n\t(note: printer name is required)\n");
695         return -1;
696 }
697
698 static int net_ads_printer_info(int argc, const char **argv)
699 {
700         ADS_STRUCT *ads;
701         ADS_STATUS rc;
702         const char *servername, *printername;
703         void *res = NULL;
704
705         if (!(ads = ads_startup())) return -1;
706
707         if (argc > 0)
708                 printername = argv[0];
709         else
710                 printername = "*";
711
712         if (argc > 1)
713                 servername =  argv[1];
714         else
715                 servername = global_myname();
716
717         rc = ads_find_printer_on_server(ads, &res, printername, servername);
718
719         if (!ADS_ERR_OK(rc)) {
720                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
721                 ads_msgfree(ads, res);
722                 return -1;
723         }
724
725         if (ads_count_replies(ads, res) == 0) {
726                 d_printf("Printer '%s' not found\n", printername);
727                 ads_msgfree(ads, res);
728                 return -1;
729         }
730
731         ads_dump(ads, res);
732         ads_msgfree(ads, res);
733
734         return 0;
735 }
736
737 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
738 {
739         return;
740 }
741
742 static int net_ads_printer_publish(int argc, const char **argv)
743 {
744         ADS_STRUCT *ads;
745         ADS_STATUS rc;
746         char *uncname, *servername;
747         ADS_PRINTER_ENTRY prt;
748         char *ports[2] = {"Samba", NULL};
749
750         /* 
751            these const strings are only here as an example.  The attributes
752            they represent are not implemented yet
753         */
754         const char *bins[] = {"Tray 21", NULL};
755         const char *media[] = {"Letter", NULL};
756         const char *orients[] = {"PORTRAIT", NULL};
757
758         if (!(ads = ads_startup())) return -1;
759
760         if (argc < 1)
761                 return net_ads_printer_usage(argc, argv);
762
763         memset(&prt, 0, sizeof(ADS_PRINTER_ENTRY));
764
765         /* we don't sue the servername or unc name provided by 
766            get_a_printer, because the server name might be
767            localhost or an ip address */
768         prt.printerName = argv[0];
769         asprintf(&servername, "%s.%s", global_myname(), ads->config.realm);
770         prt.serverName = servername;
771         prt.shortServerName = global_myname();
772         prt.versionNumber = "4";
773         asprintf(&uncname, "\\\\%s\\%s", global_myname(), argv[0]);
774         prt.uNCName=uncname;
775         prt.printBinNames = (char **) bins;
776         prt.printMediaSupported = (char **) media;
777         prt.printOrientationsSupported = (char **) orients;
778         prt.portName = (char **) ports;
779         prt.printSpooling = "PrintAfterSpooled";
780
781         rc = ads_add_printer(ads, &prt);
782         if (!ADS_ERR_OK(rc)) {
783                 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
784                 return -1;
785         }
786  
787         d_printf("published printer\n");
788  
789         return 0;
790 }
791
792 static int net_ads_printer_remove(int argc, const char **argv)
793 {
794         ADS_STRUCT *ads;
795         ADS_STATUS rc;
796         const char *servername;
797         char *prt_dn;
798         void *res = NULL;
799
800         if (!(ads = ads_startup())) return -1;
801
802         if (argc < 1)
803                 return net_ads_printer_usage(argc, argv);
804
805         if (argc > 1)
806                 servername = argv[1];
807         else
808                 servername = global_myname();
809
810         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
811
812         if (!ADS_ERR_OK(rc)) {
813                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
814                 ads_msgfree(ads, res);
815                 return -1;
816         }
817
818         if (ads_count_replies(ads, res) == 0) {
819                 d_printf("Printer '%s' not found\n", argv[1]);
820                 ads_msgfree(ads, res);
821                 return -1;
822         }
823
824         prt_dn = ads_get_dn(ads, res);
825         ads_msgfree(ads, res);
826         rc = ads_del_dn(ads, prt_dn);
827         ads_memfree(ads, prt_dn);
828
829         if (!ADS_ERR_OK(rc)) {
830                 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
831                 return -1;
832         }
833
834         return 0;
835 }
836
837 static int net_ads_printer(int argc, const char **argv)
838 {
839         struct functable func[] = {
840                 {"INFO", net_ads_printer_info},
841                 {"PUBLISH", net_ads_printer_publish},
842                 {"REMOVE", net_ads_printer_remove},
843                 {NULL, NULL}
844         };
845         
846         return net_run_function(argc, argv, func, net_ads_printer_usage);
847 }
848
849
850 static int net_ads_password(int argc, const char **argv)
851 {
852     ADS_STRUCT *ads;
853     char *auth_principal = opt_user_name;
854     char *auth_password = opt_password;
855     char *realm = NULL;
856     char *new_password = NULL;
857     char *c;
858     char *prompt;
859     ADS_STATUS ret;
860
861     
862     if ((argc != 1) || (opt_user_name == NULL) || 
863         (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
864         (strchr(argv[0], '@') == NULL)) {
865         return net_ads_usage(argc, argv);
866     }
867     
868     c = strchr(auth_principal, '@');
869     realm = ++c;
870
871     /* use the realm so we can eventually change passwords for users 
872     in realms other than default */
873     if (!(ads = ads_init(realm, NULL, NULL))) return -1;
874
875     asprintf(&prompt, "Enter new password for %s:", argv[0]);
876
877     new_password = getpass(prompt);
878
879     ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
880                                 auth_password, argv[0], new_password, ads->auth.time_offset);
881     if (!ADS_ERR_OK(ret)) {
882         d_printf("Password change failed :-( ...\n");
883         ads_destroy(&ads);
884         free(prompt);
885         return -1;
886     }
887
888     d_printf("Password change for %s completed.\n", argv[0]);
889     ads_destroy(&ads);
890     free(prompt);
891
892     return 0;
893 }
894
895
896 static int net_ads_change_localhost_pass(int argc, const char **argv)
897 {    
898     ADS_STRUCT *ads;
899     char *host_principal;
900     char *hostname;
901     ADS_STATUS ret;
902
903     if (!secrets_init()) {
904             DEBUG(1,("Failed to initialise secrets database\n"));
905             return -1;
906     }
907
908     asprintf(&opt_user_name, "%s$", global_myname());
909     opt_password = secrets_fetch_machine_password();
910
911     if (!(ads = ads_startup())) {
912             return -1;
913     }
914
915     hostname = strdup(global_myname());
916     strlower(hostname);
917     asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
918     SAFE_FREE(hostname);
919     d_printf("Changing password for principal: HOST/%s\n", host_principal);
920     
921     ret = ads_change_trust_account_password(ads, host_principal);
922
923     if (!ADS_ERR_OK(ret)) {
924         d_printf("Password change failed :-( ...\n");
925         ads_destroy(&ads);
926         SAFE_FREE(host_principal);
927         return -1;
928     }
929     
930     d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
931     ads_destroy(&ads);
932     SAFE_FREE(host_principal);
933
934     return 0;
935 }
936
937 /*
938   help for net ads search
939 */
940 static int net_ads_search_usage(int argc, const char **argv)
941 {
942         d_printf(
943                 "\nnet ads search <expression> <attributes...>\n"\
944                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
945                 "The expression is a standard LDAP search expression, and the\n"\
946                 "attributes are a list of LDAP fields to show in the results\n\n"\
947                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
948                 );
949         net_common_flags_usage(argc, argv);
950         return -1;
951 }
952
953
954 /*
955   general ADS search function. Useful in diagnosing problems in ADS
956 */
957 static int net_ads_search(int argc, const char **argv)
958 {
959         ADS_STRUCT *ads;
960         ADS_STATUS rc;
961         const char *exp;
962         const char **attrs;
963         void *res = NULL;
964
965         if (argc < 1) {
966                 return net_ads_search_usage(argc, argv);
967         }
968
969         if (!(ads = ads_startup())) {
970                 return -1;
971         }
972
973         exp = argv[0];
974         attrs = (argv + 1);
975
976         rc = ads_do_search_all(ads, ads->config.bind_path, 
977                                LDAP_SCOPE_SUBTREE,
978                                exp, attrs, &res);
979         if (!ADS_ERR_OK(rc)) {
980                 d_printf("search failed: %s\n", ads_errstr(rc));
981                 return -1;
982         }       
983
984         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
985
986         /* dump the results */
987         ads_dump(ads, res);
988
989         ads_msgfree(ads, res);
990         ads_destroy(&ads);
991
992         return 0;
993 }
994
995
996 int net_ads_help(int argc, const char **argv)
997 {
998         struct functable func[] = {
999                 {"USER", net_ads_user_usage},
1000                 {"GROUP", net_ads_group_usage},
1001                 {"PRINTER", net_ads_printer_usage},
1002                 {"SEARCH", net_ads_search_usage},
1003 #if 0
1004                 {"INFO", net_ads_info},
1005                 {"JOIN", net_ads_join},
1006                 {"LEAVE", net_ads_leave},
1007                 {"STATUS", net_ads_status},
1008                 {"PASSWORD", net_ads_password},
1009                 {"CHOSTPASS", net_ads_change_localhost_pass},
1010 #endif
1011                 {NULL, NULL}
1012         };
1013
1014         return net_run_function(argc, argv, func, net_ads_usage);
1015 }
1016
1017 int net_ads(int argc, const char **argv)
1018 {
1019         struct functable func[] = {
1020                 {"INFO", net_ads_info},
1021                 {"JOIN", net_ads_join},
1022                 {"TESTJOIN", net_ads_testjoin},
1023                 {"LEAVE", net_ads_leave},
1024                 {"STATUS", net_ads_status},
1025                 {"USER", net_ads_user},
1026                 {"GROUP", net_ads_group},
1027                 {"PASSWORD", net_ads_password},
1028                 {"CHOSTPASS", net_ads_change_localhost_pass},
1029                 {"PRINTER", net_ads_printer},
1030                 {"SEARCH", net_ads_search},
1031                 {"WORKGROUP", net_ads_workgroup},
1032                 {"LOOKUP", net_ads_lookup},
1033                 {"HELP", net_ads_help},
1034                 {NULL, NULL}
1035         };
1036         
1037         return net_run_function(argc, argv, func, net_ads_usage);
1038 }
1039
1040 #else
1041
1042 static int net_ads_noads(void)
1043 {
1044         d_printf("ADS support not compiled in\n");
1045         return -1;
1046 }
1047
1048 int net_ads_usage(int argc, const char **argv)
1049 {
1050         return net_ads_noads();
1051 }
1052
1053 int net_ads_help(int argc, const char **argv)
1054 {
1055         return net_ads_noads();
1056 }
1057
1058 int net_ads_join(int argc, const char **argv)
1059 {
1060         return net_ads_noads();
1061 }
1062
1063 int net_ads_user(int argc, const char **argv)
1064 {
1065         return net_ads_noads();
1066 }
1067
1068 int net_ads_group(int argc, const char **argv)
1069 {
1070         return net_ads_noads();
1071 }
1072
1073 /* this one shouldn't display a message */
1074 int net_ads_check(void)
1075 {
1076         return -1;
1077 }
1078
1079 int net_ads(int argc, const char **argv)
1080 {
1081         return net_ads_usage(argc, argv);
1082 }
1083
1084 #endif