first public release of samba4 code
[jelmer/samba4-debian.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 "\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, lp_netbios_name());
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", lp_netbios_name());
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$", lp_netbios_name());
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, lp_netbios_name());
576         if (!ADS_ERR_OK(rc)) {
577             d_printf("Failed to delete host '%s' from the '%s' realm.\n", 
578                      lp_netbios_name(), ads->config.realm);
579             return -1;
580         }
581
582         d_printf("Removed '%s' from realm '%s'\n", lp_netbios_name(), 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$", lp_netbios_name());
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, lp_netbios_name(), 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, lp_netbios_name(), 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", lp_netbios_name(), 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 = lp_netbios_name();
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 = lp_netbios_name();
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, lp_netbios_name(), 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 = lp_netbios_name();
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     asprintf(&prompt, "Enter new password for %s:", argv[0]);
903
904     new_password = getpass(prompt);
905
906     ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
907                                 auth_password, argv[0], new_password, ads->auth.time_offset);
908     if (!ADS_ERR_OK(ret)) {
909         d_printf("Password change failed :-( ...\n");
910         ads_destroy(&ads);
911         free(prompt);
912         return -1;
913     }
914
915     d_printf("Password change for %s completed.\n", argv[0]);
916     ads_destroy(&ads);
917     free(prompt);
918
919     return 0;
920 }
921
922
923 static int net_ads_change_localhost_pass(int argc, const char **argv)
924 {    
925     ADS_STRUCT *ads;
926     char *host_principal;
927     char *hostname;
928     ADS_STATUS ret;
929     char *user_name;
930
931     if (!secrets_init()) {
932             DEBUG(1,("Failed to initialise secrets database\n"));
933             return -1;
934     }
935
936     asprintf(&user_name, "%s$", lp_netbios_name());
937     opt_user_name = user_name;
938
939     opt_password = secrets_fetch_machine_password();
940
941     use_in_memory_ccache();
942
943     if (!(ads = ads_startup())) {
944             return -1;
945     }
946
947     hostname = strdup(lp_netbios_name());
948     strlower(hostname);
949     asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
950     SAFE_FREE(hostname);
951     d_printf("Changing password for principal: HOST/%s\n", host_principal);
952     
953     ret = ads_change_trust_account_password(ads, host_principal);
954
955     if (!ADS_ERR_OK(ret)) {
956         d_printf("Password change failed :-( ...\n");
957         ads_destroy(&ads);
958         SAFE_FREE(host_principal);
959         return -1;
960     }
961     
962     d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
963     ads_destroy(&ads);
964     SAFE_FREE(host_principal);
965
966     return 0;
967 }
968
969 /*
970   help for net ads search
971 */
972 static int net_ads_search_usage(int argc, const char **argv)
973 {
974         d_printf(
975                 "\nnet ads search <expression> <attributes...>\n"\
976                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
977                 "The expression is a standard LDAP search expression, and the\n"\
978                 "attributes are a list of LDAP fields to show in the results\n\n"\
979                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
980                 );
981         net_common_flags_usage(argc, argv);
982         return -1;
983 }
984
985
986 /*
987   general ADS search function. Useful in diagnosing problems in ADS
988 */
989 static int net_ads_search(int argc, const char **argv)
990 {
991         ADS_STRUCT *ads;
992         ADS_STATUS rc;
993         const char *exp;
994         const char **attrs;
995         void *res = NULL;
996
997         if (argc < 1) {
998                 return net_ads_search_usage(argc, argv);
999         }
1000
1001         if (!(ads = ads_startup())) {
1002                 return -1;
1003         }
1004
1005         exp = argv[0];
1006         attrs = (argv + 1);
1007
1008         rc = ads_do_search_all(ads, ads->config.bind_path,
1009                                LDAP_SCOPE_SUBTREE,
1010                                exp, attrs, &res);
1011         if (!ADS_ERR_OK(rc)) {
1012                 d_printf("search failed: %s\n", ads_errstr(rc));
1013                 return -1;
1014         }       
1015
1016         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1017
1018         /* dump the results */
1019         ads_dump(ads, res);
1020
1021         ads_msgfree(ads, res);
1022         ads_destroy(&ads);
1023
1024         return 0;
1025 }
1026
1027
1028 /*
1029   help for net ads search
1030 */
1031 static int net_ads_dn_usage(int argc, const char **argv)
1032 {
1033         d_printf(
1034                 "\nnet ads dn <dn> <attributes...>\n"\
1035                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1036                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1037                 "to show in the results\n\n"\
1038                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1039                 );
1040         net_common_flags_usage(argc, argv);
1041         return -1;
1042 }
1043
1044
1045 /*
1046   general ADS search function. Useful in diagnosing problems in ADS
1047 */
1048 static int net_ads_dn(int argc, const char **argv)
1049 {
1050         ADS_STRUCT *ads;
1051         ADS_STATUS rc;
1052         const char *dn;
1053         const char **attrs;
1054         void *res = NULL;
1055
1056         if (argc < 1) {
1057                 return net_ads_dn_usage(argc, argv);
1058         }
1059
1060         if (!(ads = ads_startup())) {
1061                 return -1;
1062         }
1063
1064         dn = argv[0];
1065         attrs = (argv + 1);
1066
1067         rc = ads_do_search_all(ads, dn, 
1068                                LDAP_SCOPE_BASE,
1069                                "(objectclass=*)", attrs, &res);
1070         if (!ADS_ERR_OK(rc)) {
1071                 d_printf("search failed: %s\n", ads_errstr(rc));
1072                 return -1;
1073         }       
1074
1075         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1076
1077         /* dump the results */
1078         ads_dump(ads, res);
1079
1080         ads_msgfree(ads, res);
1081         ads_destroy(&ads);
1082
1083         return 0;
1084 }
1085
1086
1087 int net_ads_help(int argc, const char **argv)
1088 {
1089         struct functable func[] = {
1090                 {"USER", net_ads_user_usage},
1091                 {"GROUP", net_ads_group_usage},
1092                 {"PRINTER", net_ads_printer_usage},
1093                 {"SEARCH", net_ads_search_usage},
1094 #if 0
1095                 {"INFO", net_ads_info},
1096                 {"JOIN", net_ads_join},
1097                 {"LEAVE", net_ads_leave},
1098                 {"STATUS", net_ads_status},
1099                 {"PASSWORD", net_ads_password},
1100                 {"CHOSTPASS", net_ads_change_localhost_pass},
1101 #endif
1102                 {NULL, NULL}
1103         };
1104
1105         return net_run_function(argc, argv, func, net_ads_usage);
1106 }
1107
1108 int net_ads(int argc, const char **argv)
1109 {
1110         struct functable func[] = {
1111                 {"INFO", net_ads_info},
1112                 {"JOIN", net_ads_join},
1113                 {"TESTJOIN", net_ads_testjoin},
1114                 {"LEAVE", net_ads_leave},
1115                 {"STATUS", net_ads_status},
1116                 {"USER", net_ads_user},
1117                 {"GROUP", net_ads_group},
1118                 {"PASSWORD", net_ads_password},
1119                 {"CHOSTPASS", net_ads_change_localhost_pass},
1120                 {"PRINTER", net_ads_printer},
1121                 {"SEARCH", net_ads_search},
1122                 {"DN", net_ads_dn},
1123                 {"WORKGROUP", net_ads_workgroup},
1124                 {"LOOKUP", net_ads_lookup},
1125                 {"HELP", net_ads_help},
1126                 {NULL, NULL}
1127         };
1128         
1129         return net_run_function(argc, argv, func, net_ads_usage);
1130 }
1131
1132 #else
1133
1134 static int net_ads_noads(void)
1135 {
1136         d_printf("ADS support not compiled in\n");
1137         return -1;
1138 }
1139
1140 int net_ads_usage(int argc, const char **argv)
1141 {
1142         return net_ads_noads();
1143 }
1144
1145 int net_ads_help(int argc, const char **argv)
1146 {
1147         return net_ads_noads();
1148 }
1149
1150 int net_ads_join(int argc, const char **argv)
1151 {
1152         return net_ads_noads();
1153 }
1154
1155 int net_ads_user(int argc, const char **argv)
1156 {
1157         return net_ads_noads();
1158 }
1159
1160 int net_ads_group(int argc, const char **argv)
1161 {
1162         return net_ads_noads();
1163 }
1164
1165 /* this one shouldn't display a message */
1166 int net_ads_check(void)
1167 {
1168         return -1;
1169 }
1170
1171 int net_ads(int argc, const char **argv)
1172 {
1173         return net_ads_usage(argc, argv);
1174 }
1175
1176 #endif