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