Fix bug #137: krb5_set_password is already defined in MIT 1.3 libs, so
[samba.git] / source / utils / net_ads.c
1 /* 
2    Samba Unix/Linux SMB client library 
3    net ads commands
4    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
21 */
22
23 #include "includes.h"
24 #include "../utils/net.h"
25
26 #ifdef HAVE_ADS
27
28 int net_ads_usage(int argc, const char **argv)
29 {
30         d_printf(
31 "\nnet ads join <org_unit>"\
32 "\n\tjoins the local machine to a ADS realm\n"\
33 "\nnet ads leave"\
34 "\n\tremoves the local machine from a ADS realm\n"\
35 "\nnet ads testjoin"\
36 "\n\ttests that an exiting join is OK\n"\
37 "\nnet ads user"\
38 "\n\tlist, add, or delete users in the realm\n"\
39 "\nnet ads group"\
40 "\n\tlist, add, or delete groups in the realm\n"\
41 "\nnet ads info"\
42 "\n\tshows some info on the server\n"\
43 "\nnet ads status"\
44 "\n\tdump the machine account details to stdout\n"
45 "\nnet ads lookup"\
46 "\n\tperform a CLDAP search on the server\n"
47 "\nnet ads password <username@realm> -Uadmin_username@realm%%admin_pass"\
48 "\n\tchange a user's password using an admin account"\
49 "\n\t(note: use realm in UPPERCASE)\n"\
50 "\nnet ads 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(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 info <printer> <server>"
730 "\n\tlookup info in directory for printer on server"
731 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
732 "\nnet ads printer publish <printername>"
733 "\n\tpublish printer in directory"
734 "\n\t(note: printer name is required)\n"
735 "\nnet ads printer remove <printername>"
736 "\n\tremove printer from directory"
737 "\n\t(note: printer name is required)\n");
738         return -1;
739 }
740
741 static int net_ads_printer_info(int argc, const char **argv)
742 {
743         ADS_STRUCT *ads;
744         ADS_STATUS rc;
745         const char *servername, *printername;
746         void *res = NULL;
747
748         if (!(ads = ads_startup())) return -1;
749
750         if (argc > 0)
751                 printername = argv[0];
752         else
753                 printername = "*";
754
755         if (argc > 1)
756                 servername =  argv[1];
757         else
758                 servername = global_myname();
759
760         rc = ads_find_printer_on_server(ads, &res, printername, servername);
761
762         if (!ADS_ERR_OK(rc)) {
763                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
764                 ads_msgfree(ads, res);
765                 return -1;
766         }
767
768         if (ads_count_replies(ads, res) == 0) {
769                 d_printf("Printer '%s' not found\n", printername);
770                 ads_msgfree(ads, res);
771                 return -1;
772         }
773
774         ads_dump(ads, res);
775         ads_msgfree(ads, res);
776
777         return 0;
778 }
779
780 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
781 {
782         return;
783 }
784
785 static int net_ads_printer_publish(int argc, const char **argv)
786 {
787         ADS_STRUCT *ads;
788         ADS_STATUS rc;
789         const char *servername;
790         struct cli_state *cli;
791         struct in_addr          server_ip;
792         NTSTATUS nt_status;
793         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
794         ADS_MODLIST mods = ads_init_mods(mem_ctx);
795         char *prt_dn, *srv_dn, **srv_cn;
796         void *res = NULL;
797
798         if (!(ads = ads_startup())) return -1;
799
800         if (argc < 1)
801                 return net_ads_printer_usage(argc, argv);
802         
803         if (argc == 2)
804                 servername = argv[1];
805         else
806                 servername = global_myname();
807                 
808         ads_find_machine_acct(ads, &res, servername);
809         srv_dn = ldap_get_dn(ads->ld, res);
810         srv_cn = ldap_explode_dn(srv_dn, 1);
811         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], argv[0], srv_dn);
812
813         resolve_name(servername, &server_ip, 0x20);
814
815         nt_status = cli_full_connection(&cli, global_myname(), servername, 
816                                         &server_ip, 0,
817                                         "IPC$", "IPC",  
818                                         opt_user_name, opt_workgroup,
819                                         opt_password ? opt_password : "", 
820                                         CLI_FULL_CONNECTION_USE_KERBEROS, 
821                                         NULL);
822
823         cli_nt_session_open(cli, PI_SPOOLSS);
824         get_remote_printer_publishing_data(cli, mem_ctx, &mods, argv[0]);
825
826         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
827         if (!ADS_ERR_OK(rc)) {
828                 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
829                 return -1;
830         }
831  
832         d_printf("published printer\n");
833  
834         return 0;
835 }
836
837 static int net_ads_printer_remove(int argc, const char **argv)
838 {
839         ADS_STRUCT *ads;
840         ADS_STATUS rc;
841         const char *servername;
842         char *prt_dn;
843         void *res = NULL;
844
845         if (!(ads = ads_startup())) return -1;
846
847         if (argc < 1)
848                 return net_ads_printer_usage(argc, argv);
849
850         if (argc > 1)
851                 servername = argv[1];
852         else
853                 servername = global_myname();
854
855         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
856
857         if (!ADS_ERR_OK(rc)) {
858                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
859                 ads_msgfree(ads, res);
860                 return -1;
861         }
862
863         if (ads_count_replies(ads, res) == 0) {
864                 d_printf("Printer '%s' not found\n", argv[1]);
865                 ads_msgfree(ads, res);
866                 return -1;
867         }
868
869         prt_dn = ads_get_dn(ads, res);
870         ads_msgfree(ads, res);
871         rc = ads_del_dn(ads, prt_dn);
872         ads_memfree(ads, prt_dn);
873
874         if (!ADS_ERR_OK(rc)) {
875                 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
876                 return -1;
877         }
878
879         return 0;
880 }
881
882 static int net_ads_printer(int argc, const char **argv)
883 {
884         struct functable func[] = {
885                 {"INFO", net_ads_printer_info},
886                 {"PUBLISH", net_ads_printer_publish},
887                 {"REMOVE", net_ads_printer_remove},
888                 {NULL, NULL}
889         };
890         
891         return net_run_function(argc, argv, func, net_ads_printer_usage);
892 }
893
894
895 static int net_ads_password(int argc, const char **argv)
896 {
897     ADS_STRUCT *ads;
898     const char *auth_principal = opt_user_name;
899     const char *auth_password = opt_password;
900     char *realm = NULL;
901     char *new_password = NULL;
902     char *c;
903     char *prompt;
904     ADS_STATUS ret;
905
906     
907     if ((argc != 1) || (opt_user_name == NULL) || 
908         (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
909         (strchr(argv[0], '@') == NULL)) {
910         return net_ads_usage(argc, argv);
911     }
912
913     use_in_memory_ccache();    
914     c = strchr(auth_principal, '@');
915     realm = ++c;
916
917     /* use the realm so we can eventually change passwords for users 
918     in realms other than default */
919     if (!(ads = ads_init(realm, NULL, NULL))) return -1;
920
921     /* we don't actually need a full connect, but it's the easy way to
922        fill in the KDC's addresss */
923     ads_connect(ads);
924     
925     if (!ads || !ads->config.realm) {
926             d_printf("Didn't find the kerberos server!\n");
927             return -1;
928     }
929
930     asprintf(&prompt, "Enter new password for %s:", argv[0]);
931
932     new_password = getpass(prompt);
933
934     ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
935                                 auth_password, argv[0], new_password, ads->auth.time_offset);
936     if (!ADS_ERR_OK(ret)) {
937         d_printf("Password change failed :-( ...\n");
938         ads_destroy(&ads);
939         free(prompt);
940         return -1;
941     }
942
943     d_printf("Password change for %s completed.\n", argv[0]);
944     ads_destroy(&ads);
945     free(prompt);
946
947     return 0;
948 }
949
950
951 int net_ads_changetrustpw(int argc, const char **argv)
952 {    
953     ADS_STRUCT *ads;
954     char *host_principal;
955     char *hostname;
956     ADS_STATUS ret;
957     char *user_name;
958
959     if (!secrets_init()) {
960             DEBUG(1,("Failed to initialise secrets database\n"));
961             return -1;
962     }
963
964     asprintf(&user_name, "%s$", global_myname());
965     opt_user_name = user_name;
966
967     opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
968
969     use_in_memory_ccache();
970
971     if (!(ads = ads_startup())) {
972             return -1;
973     }
974
975     hostname = strdup(global_myname());
976     strlower(hostname);
977     asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
978     SAFE_FREE(hostname);
979     d_printf("Changing password for principal: HOST/%s\n", host_principal);
980     
981     ret = ads_change_trust_account_password(ads, host_principal);
982
983     if (!ADS_ERR_OK(ret)) {
984         d_printf("Password change failed :-( ...\n");
985         ads_destroy(&ads);
986         SAFE_FREE(host_principal);
987         return -1;
988     }
989     
990     d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
991     ads_destroy(&ads);
992     SAFE_FREE(host_principal);
993
994     return 0;
995 }
996
997 /*
998   help for net ads search
999 */
1000 static int net_ads_search_usage(int argc, const char **argv)
1001 {
1002         d_printf(
1003                 "\nnet ads search <expression> <attributes...>\n"\
1004                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1005                 "The expression is a standard LDAP search expression, and the\n"\
1006                 "attributes are a list of LDAP fields to show in the results\n\n"\
1007                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1008                 );
1009         net_common_flags_usage(argc, argv);
1010         return -1;
1011 }
1012
1013
1014 /*
1015   general ADS search function. Useful in diagnosing problems in ADS
1016 */
1017 static int net_ads_search(int argc, const char **argv)
1018 {
1019         ADS_STRUCT *ads;
1020         ADS_STATUS rc;
1021         const char *exp;
1022         const char **attrs;
1023         void *res = NULL;
1024
1025         if (argc < 1) {
1026                 return net_ads_search_usage(argc, argv);
1027         }
1028
1029         if (!(ads = ads_startup())) {
1030                 return -1;
1031         }
1032
1033         exp = argv[0];
1034         attrs = (argv + 1);
1035
1036         rc = ads_do_search_all(ads, ads->config.bind_path,
1037                                LDAP_SCOPE_SUBTREE,
1038                                exp, attrs, &res);
1039         if (!ADS_ERR_OK(rc)) {
1040                 d_printf("search failed: %s\n", ads_errstr(rc));
1041                 return -1;
1042         }       
1043
1044         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1045
1046         /* dump the results */
1047         ads_dump(ads, res);
1048
1049         ads_msgfree(ads, res);
1050         ads_destroy(&ads);
1051
1052         return 0;
1053 }
1054
1055
1056 /*
1057   help for net ads search
1058 */
1059 static int net_ads_dn_usage(int argc, const char **argv)
1060 {
1061         d_printf(
1062                 "\nnet ads dn <dn> <attributes...>\n"\
1063                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1064                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1065                 "to show in the results\n\n"\
1066                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1067                 );
1068         net_common_flags_usage(argc, argv);
1069         return -1;
1070 }
1071
1072
1073 /*
1074   general ADS search function. Useful in diagnosing problems in ADS
1075 */
1076 static int net_ads_dn(int argc, const char **argv)
1077 {
1078         ADS_STRUCT *ads;
1079         ADS_STATUS rc;
1080         const char *dn;
1081         const char **attrs;
1082         void *res = NULL;
1083
1084         if (argc < 1) {
1085                 return net_ads_dn_usage(argc, argv);
1086         }
1087
1088         if (!(ads = ads_startup())) {
1089                 return -1;
1090         }
1091
1092         dn = argv[0];
1093         attrs = (argv + 1);
1094
1095         rc = ads_do_search_all(ads, dn, 
1096                                LDAP_SCOPE_BASE,
1097                                "(objectclass=*)", attrs, &res);
1098         if (!ADS_ERR_OK(rc)) {
1099                 d_printf("search failed: %s\n", ads_errstr(rc));
1100                 return -1;
1101         }       
1102
1103         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1104
1105         /* dump the results */
1106         ads_dump(ads, res);
1107
1108         ads_msgfree(ads, res);
1109         ads_destroy(&ads);
1110
1111         return 0;
1112 }
1113
1114
1115 int net_ads_help(int argc, const char **argv)
1116 {
1117         struct functable func[] = {
1118                 {"USER", net_ads_user_usage},
1119                 {"GROUP", net_ads_group_usage},
1120                 {"PRINTER", net_ads_printer_usage},
1121                 {"SEARCH", net_ads_search_usage},
1122 #if 0
1123                 {"INFO", net_ads_info},
1124                 {"JOIN", net_ads_join},
1125                 {"LEAVE", net_ads_leave},
1126                 {"STATUS", net_ads_status},
1127                 {"PASSWORD", net_ads_password},
1128                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1129 #endif
1130                 {NULL, NULL}
1131         };
1132
1133         return net_run_function(argc, argv, func, net_ads_usage);
1134 }
1135
1136 int net_ads(int argc, const char **argv)
1137 {
1138         struct functable func[] = {
1139                 {"INFO", net_ads_info},
1140                 {"JOIN", net_ads_join},
1141                 {"TESTJOIN", net_ads_testjoin},
1142                 {"LEAVE", net_ads_leave},
1143                 {"STATUS", net_ads_status},
1144                 {"USER", net_ads_user},
1145                 {"GROUP", net_ads_group},
1146                 {"PASSWORD", net_ads_password},
1147                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1148                 {"PRINTER", net_ads_printer},
1149                 {"SEARCH", net_ads_search},
1150                 {"DN", net_ads_dn},
1151                 {"WORKGROUP", net_ads_workgroup},
1152                 {"LOOKUP", net_ads_lookup},
1153                 {"HELP", net_ads_help},
1154                 {NULL, NULL}
1155         };
1156         
1157         return net_run_function(argc, argv, func, net_ads_usage);
1158 }
1159
1160 #else
1161
1162 static int net_ads_noads(void)
1163 {
1164         d_printf("ADS support not compiled in\n");
1165         return -1;
1166 }
1167
1168 int net_ads_usage(int argc, const char **argv)
1169 {
1170         return net_ads_noads();
1171 }
1172
1173 int net_ads_help(int argc, const char **argv)
1174 {
1175         return net_ads_noads();
1176 }
1177
1178 int net_ads_changetrustpw(int argc, const char **argv)
1179 {
1180         return net_ads_noads();
1181 }
1182
1183 int net_ads_join(int argc, const char **argv)
1184 {
1185         return net_ads_noads();
1186 }
1187
1188 int net_ads_user(int argc, const char **argv)
1189 {
1190         return net_ads_noads();
1191 }
1192
1193 int net_ads_group(int argc, const char **argv)
1194 {
1195         return net_ads_noads();
1196 }
1197
1198 /* this one shouldn't display a message */
1199 int net_ads_check(void)
1200 {
1201         return -1;
1202 }
1203
1204 int net_ads(int argc, const char **argv)
1205 {
1206         return net_ads_usage(argc, argv);
1207 }
1208
1209 #endif