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