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