Store the type of 'sec channel' that we establish to the DC. If we are a
[kai/samba-autobuild/.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         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(opt_target_workgroup, NULL, NULL);
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(opt_target_workgroup, NULL, NULL);
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         uint32 sec_channel_type;
652         uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
653
654         if (argc > 0) org_unit = argv[0];
655
656         if (!secrets_init()) {
657                 DEBUG(1,("Failed to initialise secrets database\n"));
658                 return -1;
659         }
660
661         /* check what type of join 
662            TODO: make this variable like RPC
663         */
664         account_type = UF_WORKSTATION_TRUST_ACCOUNT;
665
666         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
667         password = strdup(tmp_password);
668
669         if (!(ads = ads_startup())) return -1;
670
671         ou_str = ads_ou_string(org_unit);
672         asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
673         free(ou_str);
674
675         rc = ads_search_dn(ads, &res, dn, NULL);
676         ads_msgfree(ads, res);
677
678         if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
679                 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", 
680                          org_unit, dn);
681                 return -1;
682         }
683         free(dn);
684
685         if (!ADS_ERR_OK(rc)) {
686                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
687                 return -1;
688         }       
689
690         rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
691         if (!ADS_ERR_OK(rc)) {
692                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
693                 return -1;
694         }
695
696         rc = ads_domain_sid(ads, &dom_sid);
697         if (!ADS_ERR_OK(rc)) {
698                 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
699                 return -1;
700         }
701
702         rc = ads_set_machine_password(ads, global_myname(), password);
703         if (!ADS_ERR_OK(rc)) {
704                 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
705                 return -1;
706         }
707
708         if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
709                 DEBUG(1,("Failed to save domain sid\n"));
710                 return -1;
711         }
712
713         if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
714                 DEBUG(1,("Failed to save machine password\n"));
715                 return -1;
716         }
717
718         d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
719
720         free(password);
721
722         return 0;
723 }
724
725 int net_ads_printer_usage(int argc, const char **argv)
726 {
727         d_printf(
728 "\nnet ads printer info <printer> <server>"
729 "\n\tlookup info in directory for printer on server"
730 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
731 "\nnet ads printer publish <printername>"
732 "\n\tpublish printer in directory"
733 "\n\t(note: printer name is required)\n"
734 "\nnet ads printer remove <printername>"
735 "\n\tremove printer from directory"
736 "\n\t(note: printer name is required)\n");
737         return -1;
738 }
739
740 static int net_ads_printer_info(int argc, const char **argv)
741 {
742         ADS_STRUCT *ads;
743         ADS_STATUS rc;
744         const char *servername, *printername;
745         void *res = NULL;
746
747         if (!(ads = ads_startup())) return -1;
748
749         if (argc > 0)
750                 printername = argv[0];
751         else
752                 printername = "*";
753
754         if (argc > 1)
755                 servername =  argv[1];
756         else
757                 servername = global_myname();
758
759         rc = ads_find_printer_on_server(ads, &res, printername, servername);
760
761         if (!ADS_ERR_OK(rc)) {
762                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
763                 ads_msgfree(ads, res);
764                 return -1;
765         }
766
767         if (ads_count_replies(ads, res) == 0) {
768                 d_printf("Printer '%s' not found\n", printername);
769                 ads_msgfree(ads, res);
770                 return -1;
771         }
772
773         ads_dump(ads, res);
774         ads_msgfree(ads, res);
775
776         return 0;
777 }
778
779 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
780 {
781         return;
782 }
783
784 static int net_ads_printer_publish(int argc, const char **argv)
785 {
786         ADS_STRUCT *ads;
787         ADS_STATUS rc;
788         const char *servername;
789         struct cli_state *cli;
790         struct in_addr          server_ip;
791         NTSTATUS nt_status;
792         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
793         ADS_MODLIST mods = ads_init_mods(mem_ctx);
794         char *prt_dn, *srv_dn, **srv_cn;
795         void *res = NULL;
796
797         if (!(ads = ads_startup())) return -1;
798
799         if (argc < 1)
800                 return net_ads_printer_usage(argc, argv);
801         
802         if (argc == 2)
803                 servername = argv[1];
804         else
805                 servername = global_myname();
806                 
807         ads_find_machine_acct(ads, &res, servername);
808         srv_dn = ldap_get_dn(ads->ld, res);
809         srv_cn = ldap_explode_dn(srv_dn, 1);
810         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], argv[0], srv_dn);
811
812         resolve_name(servername, &server_ip, 0x20);
813
814         nt_status = cli_full_connection(&cli, global_myname(), servername, 
815                                         &server_ip, 0,
816                                         "IPC$", "IPC",  
817                                         opt_user_name, opt_workgroup,
818                                         opt_password ? opt_password : "", 
819                                         CLI_FULL_CONNECTION_USE_KERBEROS, 
820                                         NULL);
821
822         cli_nt_session_open(cli, PI_SPOOLSS);
823         get_remote_printer_publishing_data(cli, mem_ctx, &mods, argv[0]);
824
825         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
826         if (!ADS_ERR_OK(rc)) {
827                 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
828                 return -1;
829         }
830  
831         d_printf("published printer\n");
832  
833         return 0;
834 }
835
836 static int net_ads_printer_remove(int argc, const char **argv)
837 {
838         ADS_STRUCT *ads;
839         ADS_STATUS rc;
840         const char *servername;
841         char *prt_dn;
842         void *res = NULL;
843
844         if (!(ads = ads_startup())) return -1;
845
846         if (argc < 1)
847                 return net_ads_printer_usage(argc, argv);
848
849         if (argc > 1)
850                 servername = argv[1];
851         else
852                 servername = global_myname();
853
854         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
855
856         if (!ADS_ERR_OK(rc)) {
857                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
858                 ads_msgfree(ads, res);
859                 return -1;
860         }
861
862         if (ads_count_replies(ads, res) == 0) {
863                 d_printf("Printer '%s' not found\n", argv[1]);
864                 ads_msgfree(ads, res);
865                 return -1;
866         }
867
868         prt_dn = ads_get_dn(ads, res);
869         ads_msgfree(ads, res);
870         rc = ads_del_dn(ads, prt_dn);
871         ads_memfree(ads, prt_dn);
872
873         if (!ADS_ERR_OK(rc)) {
874                 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
875                 return -1;
876         }
877
878         return 0;
879 }
880
881 static int net_ads_printer(int argc, const char **argv)
882 {
883         struct functable func[] = {
884                 {"INFO", net_ads_printer_info},
885                 {"PUBLISH", net_ads_printer_publish},
886                 {"REMOVE", net_ads_printer_remove},
887                 {NULL, NULL}
888         };
889         
890         return net_run_function(argc, argv, func, net_ads_printer_usage);
891 }
892
893
894 static int net_ads_password(int argc, const char **argv)
895 {
896     ADS_STRUCT *ads;
897     const char *auth_principal = opt_user_name;
898     const char *auth_password = opt_password;
899     char *realm = NULL;
900     char *new_password = NULL;
901     char *c;
902     char *prompt;
903     ADS_STATUS ret;
904
905     
906     if ((argc != 1) || (opt_user_name == NULL) || 
907         (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
908         (strchr(argv[0], '@') == NULL)) {
909         return net_ads_usage(argc, argv);
910     }
911
912     use_in_memory_ccache();    
913     c = strchr(auth_principal, '@');
914     realm = ++c;
915
916     /* use the realm so we can eventually change passwords for users 
917     in realms other than default */
918     if (!(ads = ads_init(realm, NULL, NULL))) return -1;
919
920     /* we don't actually need a full connect, but it's the easy way to
921        fill in the KDC's addresss */
922     ads_connect(ads);
923     
924     if (!ads || !ads->config.realm) {
925             d_printf("Didn't find the kerberos server!\n");
926             return -1;
927     }
928
929     asprintf(&prompt, "Enter new password for %s:", argv[0]);
930
931     new_password = getpass(prompt);
932
933     ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
934                                 auth_password, argv[0], new_password, ads->auth.time_offset);
935     if (!ADS_ERR_OK(ret)) {
936         d_printf("Password change failed :-( ...\n");
937         ads_destroy(&ads);
938         free(prompt);
939         return -1;
940     }
941
942     d_printf("Password change for %s completed.\n", argv[0]);
943     ads_destroy(&ads);
944     free(prompt);
945
946     return 0;
947 }
948
949
950 int net_ads_changetrustpw(int argc, const char **argv)
951 {    
952     ADS_STRUCT *ads;
953     char *host_principal;
954     char *hostname;
955     ADS_STATUS ret;
956     char *user_name;
957
958     if (!secrets_init()) {
959             DEBUG(1,("Failed to initialise secrets database\n"));
960             return -1;
961     }
962
963     asprintf(&user_name, "%s$", global_myname());
964     opt_user_name = user_name;
965
966     opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
967
968     use_in_memory_ccache();
969
970     if (!(ads = ads_startup())) {
971             return -1;
972     }
973
974     hostname = strdup(global_myname());
975     strlower(hostname);
976     asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
977     SAFE_FREE(hostname);
978     d_printf("Changing password for principal: HOST/%s\n", host_principal);
979     
980     ret = ads_change_trust_account_password(ads, host_principal);
981
982     if (!ADS_ERR_OK(ret)) {
983         d_printf("Password change failed :-( ...\n");
984         ads_destroy(&ads);
985         SAFE_FREE(host_principal);
986         return -1;
987     }
988     
989     d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
990     ads_destroy(&ads);
991     SAFE_FREE(host_principal);
992
993     return 0;
994 }
995
996 /*
997   help for net ads search
998 */
999 static int net_ads_search_usage(int argc, const char **argv)
1000 {
1001         d_printf(
1002                 "\nnet ads search <expression> <attributes...>\n"\
1003                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1004                 "The expression is a standard LDAP search expression, and the\n"\
1005                 "attributes are a list of LDAP fields to show in the results\n\n"\
1006                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1007                 );
1008         net_common_flags_usage(argc, argv);
1009         return -1;
1010 }
1011
1012
1013 /*
1014   general ADS search function. Useful in diagnosing problems in ADS
1015 */
1016 static int net_ads_search(int argc, const char **argv)
1017 {
1018         ADS_STRUCT *ads;
1019         ADS_STATUS rc;
1020         const char *exp;
1021         const char **attrs;
1022         void *res = NULL;
1023
1024         if (argc < 1) {
1025                 return net_ads_search_usage(argc, argv);
1026         }
1027
1028         if (!(ads = ads_startup())) {
1029                 return -1;
1030         }
1031
1032         exp = argv[0];
1033         attrs = (argv + 1);
1034
1035         rc = ads_do_search_all(ads, ads->config.bind_path,
1036                                LDAP_SCOPE_SUBTREE,
1037                                exp, attrs, &res);
1038         if (!ADS_ERR_OK(rc)) {
1039                 d_printf("search failed: %s\n", ads_errstr(rc));
1040                 return -1;
1041         }       
1042
1043         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1044
1045         /* dump the results */
1046         ads_dump(ads, res);
1047
1048         ads_msgfree(ads, res);
1049         ads_destroy(&ads);
1050
1051         return 0;
1052 }
1053
1054
1055 /*
1056   help for net ads search
1057 */
1058 static int net_ads_dn_usage(int argc, const char **argv)
1059 {
1060         d_printf(
1061                 "\nnet ads dn <dn> <attributes...>\n"\
1062                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1063                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1064                 "to show in the results\n\n"\
1065                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1066                 );
1067         net_common_flags_usage(argc, argv);
1068         return -1;
1069 }
1070
1071
1072 /*
1073   general ADS search function. Useful in diagnosing problems in ADS
1074 */
1075 static int net_ads_dn(int argc, const char **argv)
1076 {
1077         ADS_STRUCT *ads;
1078         ADS_STATUS rc;
1079         const char *dn;
1080         const char **attrs;
1081         void *res = NULL;
1082
1083         if (argc < 1) {
1084                 return net_ads_dn_usage(argc, argv);
1085         }
1086
1087         if (!(ads = ads_startup())) {
1088                 return -1;
1089         }
1090
1091         dn = argv[0];
1092         attrs = (argv + 1);
1093
1094         rc = ads_do_search_all(ads, dn, 
1095                                LDAP_SCOPE_BASE,
1096                                "(objectclass=*)", attrs, &res);
1097         if (!ADS_ERR_OK(rc)) {
1098                 d_printf("search failed: %s\n", ads_errstr(rc));
1099                 return -1;
1100         }       
1101
1102         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1103
1104         /* dump the results */
1105         ads_dump(ads, res);
1106
1107         ads_msgfree(ads, res);
1108         ads_destroy(&ads);
1109
1110         return 0;
1111 }
1112
1113
1114 int net_ads_help(int argc, const char **argv)
1115 {
1116         struct functable func[] = {
1117                 {"USER", net_ads_user_usage},
1118                 {"GROUP", net_ads_group_usage},
1119                 {"PRINTER", net_ads_printer_usage},
1120                 {"SEARCH", net_ads_search_usage},
1121 #if 0
1122                 {"INFO", net_ads_info},
1123                 {"JOIN", net_ads_join},
1124                 {"LEAVE", net_ads_leave},
1125                 {"STATUS", net_ads_status},
1126                 {"PASSWORD", net_ads_password},
1127                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1128 #endif
1129                 {NULL, NULL}
1130         };
1131
1132         return net_run_function(argc, argv, func, net_ads_usage);
1133 }
1134
1135 int net_ads(int argc, const char **argv)
1136 {
1137         struct functable func[] = {
1138                 {"INFO", net_ads_info},
1139                 {"JOIN", net_ads_join},
1140                 {"TESTJOIN", net_ads_testjoin},
1141                 {"LEAVE", net_ads_leave},
1142                 {"STATUS", net_ads_status},
1143                 {"USER", net_ads_user},
1144                 {"GROUP", net_ads_group},
1145                 {"PASSWORD", net_ads_password},
1146                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1147                 {"PRINTER", net_ads_printer},
1148                 {"SEARCH", net_ads_search},
1149                 {"DN", net_ads_dn},
1150                 {"WORKGROUP", net_ads_workgroup},
1151                 {"LOOKUP", net_ads_lookup},
1152                 {"HELP", net_ads_help},
1153                 {NULL, NULL}
1154         };
1155         
1156         return net_run_function(argc, argv, func, net_ads_usage);
1157 }
1158
1159 #else
1160
1161 static int net_ads_noads(void)
1162 {
1163         d_printf("ADS support not compiled in\n");
1164         return -1;
1165 }
1166
1167 int net_ads_usage(int argc, const char **argv)
1168 {
1169         return net_ads_noads();
1170 }
1171
1172 int net_ads_help(int argc, const char **argv)
1173 {
1174         return net_ads_noads();
1175 }
1176
1177 int net_ads_changetrustpw(int argc, const char **argv)
1178 {
1179         return net_ads_noads();
1180 }
1181
1182 int net_ads_join(int argc, const char **argv)
1183 {
1184         return net_ads_noads();
1185 }
1186
1187 int net_ads_user(int argc, const char **argv)
1188 {
1189         return net_ads_noads();
1190 }
1191
1192 int net_ads_group(int argc, const char **argv)
1193 {
1194         return net_ads_noads();
1195 }
1196
1197 /* this one shouldn't display a message */
1198 int net_ads_check(void)
1199 {
1200         return -1;
1201 }
1202
1203 int net_ads(int argc, const char **argv)
1204 {
1205         return net_ads_usage(argc, argv);
1206 }
1207
1208 #endif