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