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