r2832: Readd WKGUID-binding to match the correct default-locations of new
[tprouty/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> <password> -Uadmin_username@realm%%admin_pass"\
48 "\n\tchange a user's password using an admin account"\
49 "\n\t(note: use realm in UPPERCASE, prompts if password is obmitted)\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 "\nnet ads keytab"\
59 "\n\tcreates and updates the kerberos system keytab file\n"
60                 );
61         return -1;
62 }
63
64
65 /*
66   this implements the CLDAP based netlogon lookup requests
67   for finding the domain controller of a ADS domain
68 */
69 static int net_ads_lookup(int argc, const char **argv)
70 {
71         ADS_STRUCT *ads;
72
73         ads = ads_init(NULL, opt_target_workgroup, opt_host);
74         if (ads) {
75                 ads->auth.flags |= ADS_AUTH_NO_BIND;
76         }
77
78         ads_connect(ads);
79
80         if (!ads) {
81                 d_printf("Didn't find the cldap server!\n");
82                 return -1;
83         } if (!ads->config.realm) {
84                 ads->config.realm = opt_target_workgroup;
85                 ads->ldap_port = 389;
86         }
87
88         return ads_cldap_netlogon(ads);
89 }
90
91
92
93 static int net_ads_info(int argc, const char **argv)
94 {
95         ADS_STRUCT *ads;
96
97         ads = ads_init(NULL, opt_target_workgroup, opt_host);
98
99         if (ads) {
100                 ads->auth.flags |= ADS_AUTH_NO_BIND;
101         }
102
103         ads_connect(ads);
104
105         if (!ads || !ads->config.realm) {
106                 d_printf("Didn't find the ldap server!\n");
107                 return -1;
108         }
109
110         d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
111         d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
112         d_printf("Realm: %s\n", ads->config.realm);
113         d_printf("Bind Path: %s\n", ads->config.bind_path);
114         d_printf("LDAP port: %d\n", ads->ldap_port);
115         d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
116
117         d_printf("KDC server: %s\n", ads->auth.kdc_server );
118         d_printf("Server time offset: %d\n", ads->auth.time_offset );
119
120         return 0;
121 }
122
123 static void use_in_memory_ccache(void) {
124         /* Use in-memory credentials cache so we do not interfere with
125          * existing credentials */
126         setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
127 }
128
129 static ADS_STRUCT *ads_startup(void)
130 {
131         ADS_STRUCT *ads;
132         ADS_STATUS status;
133         BOOL need_password = False;
134         BOOL second_time = False;
135         char *cp;
136         
137         /* lp_realm() should be handled by a command line param, 
138            However, the join requires that realm be set in smb.conf
139            and compares our realm with the remote server's so this is
140            ok until someone needs more flexibility */
141            
142         ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
143
144         if (!opt_user_name) {
145                 opt_user_name = "administrator";
146         }
147
148         if (opt_user_specified) {
149                 need_password = True;
150         }
151
152 retry:
153         if (!opt_password && need_password && !opt_machine_pass) {
154                 char *prompt;
155                 asprintf(&prompt,"%s's password: ", opt_user_name);
156                 opt_password = getpass(prompt);
157                 free(prompt);
158         }
159
160         if (opt_password) {
161                 use_in_memory_ccache();
162                 ads->auth.password = smb_xstrdup(opt_password);
163         }
164
165         ads->auth.user_name = smb_xstrdup(opt_user_name);
166
167        /*
168         * If the username is of the form "name@realm", 
169         * extract the realm and convert to upper case.
170         * This is only used to establish the connection.
171         */
172        if ((cp = strchr(ads->auth.user_name, '@'))!=0) {
173                *cp++ = '\0';
174                ads->auth.realm = smb_xstrdup(cp);
175                strupper_m(ads->auth.realm);
176        }
177
178         status = ads_connect(ads);
179
180         if (!ADS_ERR_OK(status)) {
181                 if (!need_password && !second_time) {
182                         need_password = True;
183                         second_time = True;
184                         goto retry;
185                 } else {
186                         DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
187                         return NULL;
188                 }
189         }
190         return ads;
191 }
192
193
194 /*
195   Check to see if connection can be made via ads.
196   ads_startup() stores the password in opt_password if it needs to so
197   that rpc or rap can use it without re-prompting.
198 */
199 int net_ads_check(void)
200 {
201         ADS_STRUCT *ads;
202
203         ads = ads_startup();
204         if (!ads)
205                 return -1;
206         ads_destroy(&ads);
207         return 0;
208 }
209
210 /* 
211    determine the netbios workgroup name for a domain
212  */
213 static int net_ads_workgroup(int argc, const char **argv)
214 {
215         ADS_STRUCT *ads;
216         TALLOC_CTX *ctx;
217         const char *workgroup;
218
219         if (!(ads = ads_startup())) return -1;
220
221         if (!(ctx = talloc_init("net_ads_workgroup"))) {
222                 ads_destroy(&ads);
223                 return -1;
224         }
225
226         if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
227                 d_printf("Failed to find workgroup for realm '%s'\n", 
228                          ads->config.realm);
229                 talloc_destroy(ctx);
230                 ads_destroy(&ads);
231                 return -1;
232         }
233
234         d_printf("Workgroup: %s\n", workgroup);
235
236         talloc_destroy(ctx);
237         ads_destroy(&ads);
238         return 0;
239 }
240
241
242
243 static BOOL usergrp_display(char *field, void **values, void *data_area)
244 {
245         char **disp_fields = (char **) data_area;
246
247         if (!field) { /* must be end of record */
248                 if (!strchr_m(disp_fields[0], '$')) {
249                         if (disp_fields[1])
250                                 d_printf("%-21.21s %s\n", 
251                                        disp_fields[0], disp_fields[1]);
252                         else
253                                 d_printf("%s\n", disp_fields[0]);
254                 }
255                 SAFE_FREE(disp_fields[0]);
256                 SAFE_FREE(disp_fields[1]);
257                 return True;
258         }
259         if (!values) /* must be new field, indicate string field */
260                 return True;
261         if (StrCaseCmp(field, "sAMAccountName") == 0) {
262                 disp_fields[0] = strdup((char *) values[0]);
263         }
264         if (StrCaseCmp(field, "description") == 0)
265                 disp_fields[1] = strdup((char *) values[0]);
266         return True;
267 }
268
269 static int net_ads_user_usage(int argc, const char **argv)
270 {
271         return net_help_user(argc, argv);
272
273
274 static int ads_user_add(int argc, const char **argv)
275 {
276         ADS_STRUCT *ads;
277         ADS_STATUS status;
278         char *upn, *userdn;
279         void *res=NULL;
280         int rc = -1;
281
282         if (argc < 1) return net_ads_user_usage(argc, argv);
283         
284         if (!(ads = ads_startup())) {
285                 return -1;
286         }
287
288         status = ads_find_user_acct(ads, &res, argv[0]);
289
290         if (!ADS_ERR_OK(status)) {
291                 d_printf("ads_user_add: %s\n", ads_errstr(status));
292                 goto done;
293         }
294         
295         if (ads_count_replies(ads, res)) {
296                 d_printf("ads_user_add: User %s already exists\n", argv[0]);
297                 goto done;
298         }
299
300         if (opt_container == NULL) {
301                 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
302         }
303
304         status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
305
306         if (!ADS_ERR_OK(status)) {
307                 d_printf("Could not add user %s: %s\n", argv[0],
308                          ads_errstr(status));
309                 goto done;
310         }
311
312         /* if no password is to be set, we're done */
313         if (argc == 1) { 
314                 d_printf("User %s added\n", argv[0]);
315                 rc = 0;
316                 goto done;
317         }
318
319         /* try setting the password */
320         asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
321         status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1], 
322                                        ads->auth.time_offset);
323         safe_free(upn);
324         if (ADS_ERR_OK(status)) {
325                 d_printf("User %s added\n", argv[0]);
326                 rc = 0;
327                 goto done;
328         }
329
330         /* password didn't set, delete account */
331         d_printf("Could not add user %s.  Error setting password %s\n",
332                  argv[0], ads_errstr(status));
333         ads_msgfree(ads, res);
334         status=ads_find_user_acct(ads, &res, argv[0]);
335         if (ADS_ERR_OK(status)) {
336                 userdn = ads_get_dn(ads, res);
337                 ads_del_dn(ads, userdn);
338                 ads_memfree(ads, userdn);
339         }
340
341  done:
342         if (res)
343                 ads_msgfree(ads, res);
344         ads_destroy(&ads);
345         return rc;
346 }
347
348 static int ads_user_info(int argc, const char **argv)
349 {
350         ADS_STRUCT *ads;
351         ADS_STATUS rc;
352         void *res;
353         const char *attrs[] = {"memberOf", NULL};
354         char *searchstring=NULL;
355         char **grouplist;
356         char *escaped_user = escape_ldap_string_alloc(argv[0]);
357
358         if (argc < 1) {
359                 return net_ads_user_usage(argc, argv);
360         }
361         
362         if (!(ads = ads_startup())) {
363                 return -1;
364         }
365
366         if (!escaped_user) {
367                 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
368                 ads_destroy(&ads);
369                 return -1;
370         }
371
372         asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
373         rc = ads_search(ads, &res, searchstring, attrs);
374         safe_free(searchstring);
375
376         if (!ADS_ERR_OK(rc)) {
377                 d_printf("ads_search: %s\n", ads_errstr(rc));
378                 ads_destroy(&ads);
379                 return -1;
380         }
381         
382         grouplist = ldap_get_values(ads->ld, res, "memberOf");
383
384         if (grouplist) {
385                 int i;
386                 char **groupname;
387                 for (i=0;grouplist[i];i++) {
388                         groupname = ldap_explode_dn(grouplist[i], 1);
389                         d_printf("%s\n", groupname[0]);
390                         ldap_value_free(groupname);
391                 }
392                 ldap_value_free(grouplist);
393         }
394         
395         ads_msgfree(ads, res);
396         ads_destroy(&ads);
397         return 0;
398 }
399
400 static int ads_user_delete(int argc, const char **argv)
401 {
402         ADS_STRUCT *ads;
403         ADS_STATUS rc;
404         void *res;
405         char *userdn;
406
407         if (argc < 1) {
408                 return net_ads_user_usage(argc, argv);
409         }
410         
411         if (!(ads = ads_startup())) {
412                 return -1;
413         }
414
415         rc = ads_find_user_acct(ads, &res, argv[0]);
416         if (!ADS_ERR_OK(rc)) {
417                 DEBUG(0, ("User %s does not exist\n", argv[0]));
418                 ads_destroy(&ads);
419                 return -1;
420         }
421         userdn = ads_get_dn(ads, res);
422         ads_msgfree(ads, res);
423         rc = ads_del_dn(ads, userdn);
424         ads_memfree(ads, userdn);
425         if (!ADS_ERR_OK(rc)) {
426                 d_printf("User %s deleted\n", argv[0]);
427                 ads_destroy(&ads);
428                 return 0;
429         }
430         d_printf("Error deleting user %s: %s\n", argv[0], 
431                  ads_errstr(rc));
432         ads_destroy(&ads);
433         return -1;
434 }
435
436 int net_ads_user(int argc, const char **argv)
437 {
438         struct functable func[] = {
439                 {"ADD", ads_user_add},
440                 {"INFO", ads_user_info},
441                 {"DELETE", ads_user_delete},
442                 {NULL, NULL}
443         };
444         ADS_STRUCT *ads;
445         ADS_STATUS rc;
446         const char *shortattrs[] = {"sAMAccountName", NULL};
447         const char *longattrs[] = {"sAMAccountName", "description", NULL};
448         char *disp_fields[2] = {NULL, NULL};
449         
450         if (argc == 0) {
451                 if (!(ads = ads_startup())) {
452                         return -1;
453                 }
454
455                 if (opt_long_list_entries)
456                         d_printf("\nUser name             Comment"\
457                                  "\n-----------------------------\n");
458
459                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
460                                           LDAP_SCOPE_SUBTREE,
461                                           "(objectclass=user)", 
462                                           opt_long_list_entries ? longattrs :
463                                           shortattrs, usergrp_display, 
464                                           disp_fields);
465                 ads_destroy(&ads);
466                 return 0;
467         }
468
469         return net_run_function(argc, argv, func, net_ads_user_usage);
470 }
471
472 static int net_ads_group_usage(int argc, const char **argv)
473 {
474         return net_help_group(argc, argv);
475
476
477 static int ads_group_add(int argc, const char **argv)
478 {
479         ADS_STRUCT *ads;
480         ADS_STATUS status;
481         void *res=NULL;
482         int rc = -1;
483
484         if (argc < 1) {
485                 return net_ads_group_usage(argc, argv);
486         }
487         
488         if (!(ads = ads_startup())) {
489                 return -1;
490         }
491
492         status = ads_find_user_acct(ads, &res, argv[0]);
493
494         if (!ADS_ERR_OK(status)) {
495                 d_printf("ads_group_add: %s\n", ads_errstr(status));
496                 goto done;
497         }
498         
499         if (ads_count_replies(ads, res)) {
500                 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
501                 ads_msgfree(ads, res);
502                 goto done;
503         }
504
505         if (opt_container == NULL) {
506                 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
507         }
508
509         status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
510
511         if (ADS_ERR_OK(status)) {
512                 d_printf("Group %s added\n", argv[0]);
513                 rc = 0;
514         } else {
515                 d_printf("Could not add group %s: %s\n", argv[0],
516                          ads_errstr(status));
517         }
518
519  done:
520         if (res)
521                 ads_msgfree(ads, res);
522         ads_destroy(&ads);
523         return rc;
524 }
525
526 static int ads_group_delete(int argc, const char **argv)
527 {
528         ADS_STRUCT *ads;
529         ADS_STATUS rc;
530         void *res;
531         char *groupdn;
532
533         if (argc < 1) {
534                 return net_ads_group_usage(argc, argv);
535         }
536         
537         if (!(ads = ads_startup())) {
538                 return -1;
539         }
540
541         rc = ads_find_user_acct(ads, &res, argv[0]);
542         if (!ADS_ERR_OK(rc)) {
543                 DEBUG(0, ("Group %s does not exist\n", argv[0]));
544                 ads_destroy(&ads);
545                 return -1;
546         }
547         groupdn = ads_get_dn(ads, res);
548         ads_msgfree(ads, res);
549         rc = ads_del_dn(ads, groupdn);
550         ads_memfree(ads, groupdn);
551         if (!ADS_ERR_OK(rc)) {
552                 d_printf("Group %s deleted\n", argv[0]);
553                 ads_destroy(&ads);
554                 return 0;
555         }
556         d_printf("Error deleting group %s: %s\n", argv[0], 
557                  ads_errstr(rc));
558         ads_destroy(&ads);
559         return -1;
560 }
561
562 int net_ads_group(int argc, const char **argv)
563 {
564         struct functable func[] = {
565                 {"ADD", ads_group_add},
566                 {"DELETE", ads_group_delete},
567                 {NULL, NULL}
568         };
569         ADS_STRUCT *ads;
570         ADS_STATUS rc;
571         const char *shortattrs[] = {"sAMAccountName", NULL};
572         const char *longattrs[] = {"sAMAccountName", "description", NULL};
573         char *disp_fields[2] = {NULL, NULL};
574
575         if (argc == 0) {
576                 if (!(ads = ads_startup())) {
577                         return -1;
578                 }
579
580                 if (opt_long_list_entries)
581                         d_printf("\nGroup name            Comment"\
582                                  "\n-----------------------------\n");
583                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
584                                           LDAP_SCOPE_SUBTREE, 
585                                           "(objectclass=group)", 
586                                           opt_long_list_entries ? longattrs : 
587                                           shortattrs, usergrp_display, 
588                                           disp_fields);
589
590                 ads_destroy(&ads);
591                 return 0;
592         }
593         return net_run_function(argc, argv, func, net_ads_group_usage);
594 }
595
596 static int net_ads_status(int argc, const char **argv)
597 {
598         ADS_STRUCT *ads;
599         ADS_STATUS rc;
600         void *res;
601
602         if (!(ads = ads_startup())) {
603                 return -1;
604         }
605
606         rc = ads_find_machine_acct(ads, &res, global_myname());
607         if (!ADS_ERR_OK(rc)) {
608                 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
609                 ads_destroy(&ads);
610                 return -1;
611         }
612
613         if (ads_count_replies(ads, res) == 0) {
614                 d_printf("No machine account for '%s' found\n", global_myname());
615                 ads_destroy(&ads);
616                 return -1;
617         }
618
619         ads_dump(ads, res);
620         ads_destroy(&ads);
621         return 0;
622 }
623
624 static int net_ads_leave(int argc, const char **argv)
625 {
626         ADS_STRUCT *ads = NULL;
627         ADS_STATUS rc;
628
629         if (!secrets_init()) {
630                 DEBUG(1,("Failed to initialise secrets database\n"));
631                 return -1;
632         }
633
634         if (!opt_password) {
635                 net_use_machine_password();
636         }
637
638         if (!(ads = ads_startup())) {
639                 return -1;
640         }
641
642         rc = ads_leave_realm(ads, global_myname());
643         if (!ADS_ERR_OK(rc)) {
644                 d_printf("Failed to delete host '%s' from the '%s' realm.\n", 
645                         global_myname(), ads->config.realm);
646                 ads_destroy(&ads);
647                 return -1;
648         }
649
650         d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
651         ads_destroy(&ads);
652         return 0;
653 }
654
655 static int net_ads_join_ok(void)
656 {
657         ADS_STRUCT *ads = NULL;
658
659         if (!secrets_init()) {
660                 DEBUG(1,("Failed to initialise secrets database\n"));
661                 return -1;
662         }
663
664         net_use_machine_password();
665
666         if (!(ads = ads_startup())) {
667                 return -1;
668         }
669
670         ads_destroy(&ads);
671         return 0;
672 }
673
674 /*
675   check that an existing join is OK
676  */
677 int net_ads_testjoin(int argc, const char **argv)
678 {
679         use_in_memory_ccache();
680
681         /* Display success or failure */
682         if (net_ads_join_ok() != 0) {
683                 fprintf(stderr,"Join to domain is not valid\n");
684                 return -1;
685         }
686
687         printf("Join is OK\n");
688         return 0;
689 }
690
691 /*
692   join a domain using ADS
693  */
694 int net_ads_join(int argc, const char **argv)
695 {
696         ADS_STRUCT *ads;
697         ADS_STATUS rc;
698         char *password;
699         char *machine_account = NULL;
700         char *tmp_password;
701         const char *org_unit = NULL;
702         char *dn;
703         void *res;
704         DOM_SID dom_sid;
705         char *ou_str;
706         uint32 sec_channel_type = SEC_CHAN_WKSTA;
707         uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
708         const char *short_domain_name = NULL;
709         TALLOC_CTX *ctx = NULL;
710
711         if (argc > 0) {
712                 org_unit = argv[0];
713         }
714
715         if (!secrets_init()) {
716                 DEBUG(1,("Failed to initialise secrets database\n"));
717                 return -1;
718         }
719
720         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
721         password = strdup(tmp_password);
722
723         if (!(ads = ads_startup())) {
724                 return -1;
725         }
726
727         if (!*lp_realm()) {
728                 d_printf("realm must be set in in smb.conf for ADS join to succeed.\n");
729                 ads_destroy(&ads);
730                 return -1;
731         }
732
733         if (strcmp(ads->config.realm, lp_realm()) != 0) {
734                 d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match.  Aborting join\n", ads->config.realm, lp_realm());
735                 ads_destroy(&ads);
736                 return -1;
737         }
738
739         ou_str = ads_ou_string(ads,org_unit);
740         asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
741         free(ou_str);
742
743         rc = ads_search_dn(ads, &res, dn, NULL);
744         ads_msgfree(ads, res);
745
746         if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
747                 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", 
748                          org_unit, dn);
749                 ads_destroy(&ads);
750                 return -1;
751         }
752         free(dn);
753
754         if (!ADS_ERR_OK(rc)) {
755                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
756                 ads_destroy(&ads);
757                 return -1;
758         }       
759
760         rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
761         if (!ADS_ERR_OK(rc)) {
762                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
763                 ads_destroy(&ads);
764                 return -1;
765         }
766
767         rc = ads_domain_sid(ads, &dom_sid);
768         if (!ADS_ERR_OK(rc)) {
769                 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));       
770                 ads_destroy(&ads);
771                 return -1;
772         }
773
774         if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
775                 d_printf("asprintf failed\n");
776                 ads_destroy(&ads);
777                 return -1;
778         }
779
780         rc = ads_set_machine_password(ads, machine_account, password);
781         if (!ADS_ERR_OK(rc)) {
782                 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
783                 ads_destroy(&ads);
784                 return -1;
785         }
786         
787         /* make sure we get the right workgroup */
788         
789         if ( !(ctx = talloc_init("net ads join")) ) {
790                 d_printf("talloc_init() failed!\n");
791                 ads_destroy(&ads);
792                 return -1;
793         }
794         
795         rc = ads_workgroup_name(ads, ctx, &short_domain_name);
796         if ( ADS_ERR_OK(rc) ) {
797                 if ( !strequal(lp_workgroup(), short_domain_name) ) {
798                         d_printf("The workgroup in smb.conf does not match the short\n");
799                         d_printf("domain name obtained from the server.\n");
800                         d_printf("Using the name [%s] from the server.\n", short_domain_name);
801                         d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
802                 }
803         } else {
804                 short_domain_name = lp_workgroup();
805         }
806         
807         d_printf("Using short domain name -- %s\n", short_domain_name);
808         
809         /*  HACK ALRET!  Store the sid and password under bother the lp_workgroup() 
810             value from smb.conf and the string returned from the server.  The former is
811             neede to bootstrap winbindd's first connection to the DC to get the real 
812             short domain name   --jerry */
813             
814         if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
815                 DEBUG(1,("Failed to save domain sid\n"));
816                 ads_destroy(&ads);
817                 return -1;
818         }
819
820         if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
821                 DEBUG(1,("Failed to save machine password\n"));
822                 ads_destroy(&ads);
823                 return -1;
824         }
825
826         if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
827                 DEBUG(1,("Failed to save domain sid\n"));
828                 ads_destroy(&ads);
829                 return -1;
830         }
831
832         if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
833                 DEBUG(1,("Failed to save machine password\n"));
834                 ads_destroy(&ads);
835                 return -1;
836         }
837         
838         /* Now build the keytab, using the same ADS connection */
839         if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
840                 DEBUG(1,("Error creating host keytab!\n"));
841         }
842
843         d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
844
845         SAFE_FREE(password);
846         SAFE_FREE(machine_account);
847         if ( ctx ) {
848                 talloc_destroy(ctx);
849         }
850         ads_destroy(&ads);
851         return 0;
852 }
853
854 int net_ads_printer_usage(int argc, const char **argv)
855 {
856         d_printf(
857 "\nnet ads printer search <printer>"
858 "\n\tsearch for a printer in the directory\n"
859 "\nnet ads printer info <printer> <server>"
860 "\n\tlookup info in directory for printer on server"
861 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
862 "\nnet ads printer publish <printername>"
863 "\n\tpublish printer in directory"
864 "\n\t(note: printer name is required)\n"
865 "\nnet ads printer remove <printername>"
866 "\n\tremove printer from directory"
867 "\n\t(note: printer name is required)\n");
868         return -1;
869 }
870
871 static int net_ads_printer_search(int argc, const char **argv)
872 {
873         ADS_STRUCT *ads;
874         ADS_STATUS rc;
875         void *res = NULL;
876
877         if (!(ads = ads_startup())) {
878                 return -1;
879         }
880
881         rc = ads_find_printers(ads, &res);
882
883         if (!ADS_ERR_OK(rc)) {
884                 d_printf("ads_find_printer: %s\n", ads_errstr(rc));
885                 ads_msgfree(ads, res);
886                 ads_destroy(&ads);
887                 return -1;
888         }
889
890         if (ads_count_replies(ads, res) == 0) {
891                 d_printf("No results found\n");
892                 ads_msgfree(ads, res);
893                 ads_destroy(&ads);
894                 return -1;
895         }
896
897         ads_dump(ads, res);
898         ads_msgfree(ads, res);
899         ads_destroy(&ads);
900         return 0;
901 }
902
903 static int net_ads_printer_info(int argc, const char **argv)
904 {
905         ADS_STRUCT *ads;
906         ADS_STATUS rc;
907         const char *servername, *printername;
908         void *res = NULL;
909
910         if (!(ads = ads_startup())) {
911                 return -1;
912         }
913
914         if (argc > 0) {
915                 printername = argv[0];
916         } else {
917                 printername = "*";
918         }
919
920         if (argc > 1) {
921                 servername =  argv[1];
922         } else {
923                 servername = global_myname();
924         }
925
926         rc = ads_find_printer_on_server(ads, &res, printername, servername);
927
928         if (!ADS_ERR_OK(rc)) {
929                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
930                 ads_msgfree(ads, res);
931                 ads_destroy(&ads);
932                 return -1;
933         }
934
935         if (ads_count_replies(ads, res) == 0) {
936                 d_printf("Printer '%s' not found\n", printername);
937                 ads_msgfree(ads, res);
938                 ads_destroy(&ads);
939                 return -1;
940         }
941
942         ads_dump(ads, res);
943         ads_msgfree(ads, res);
944         ads_destroy(&ads);
945
946         return 0;
947 }
948
949 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
950 {
951         return;
952 }
953
954 static int net_ads_printer_publish(int argc, const char **argv)
955 {
956         ADS_STRUCT *ads;
957         ADS_STATUS rc;
958         const char *servername, *printername;
959         struct cli_state *cli;
960         struct in_addr          server_ip;
961         NTSTATUS nt_status;
962         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
963         ADS_MODLIST mods = ads_init_mods(mem_ctx);
964         char *prt_dn, *srv_dn, **srv_cn;
965         void *res = NULL;
966
967         if (!(ads = ads_startup())) {
968                 return -1;
969         }
970
971         if (argc < 1) {
972                 return net_ads_printer_usage(argc, argv);
973         }
974         
975         printername = argv[0];
976
977         if (argc == 2) {
978                 servername = argv[1];
979         } else {
980                 servername = global_myname();
981         }
982                 
983         /* Get printer data from SPOOLSS */
984
985         resolve_name(servername, &server_ip, 0x20);
986
987         nt_status = cli_full_connection(&cli, global_myname(), servername, 
988                                         &server_ip, 0,
989                                         "IPC$", "IPC",  
990                                         opt_user_name, opt_workgroup,
991                                         opt_password ? opt_password : "", 
992                                         CLI_FULL_CONNECTION_USE_KERBEROS, 
993                                         Undefined, NULL);
994
995         if (NT_STATUS_IS_ERR(nt_status)) {
996                 d_printf("Unable to open a connnection to %s to obtain data "
997                          "for %s\n", servername, printername);
998                 ads_destroy(&ads);
999                 return -1;
1000         }
1001
1002         /* Publish on AD server */
1003
1004         ads_find_machine_acct(ads, &res, servername);
1005
1006         if (ads_count_replies(ads, res) == 0) {
1007                 d_printf("Could not find machine account for server %s\n", 
1008                          servername);
1009                 ads_destroy(&ads);
1010                 return -1;
1011         }
1012
1013         srv_dn = ldap_get_dn(ads->ld, res);
1014         srv_cn = ldap_explode_dn(srv_dn, 1);
1015
1016         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1017
1018         cli_nt_session_open(cli, PI_SPOOLSS);
1019         get_remote_printer_publishing_data(cli, mem_ctx, &mods, printername);
1020
1021         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1022         if (!ADS_ERR_OK(rc)) {
1023                 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
1024                 ads_destroy(&ads);
1025                 return -1;
1026         }
1027  
1028         d_printf("published printer\n");
1029         ads_destroy(&ads);
1030  
1031         return 0;
1032 }
1033
1034 static int net_ads_printer_remove(int argc, const char **argv)
1035 {
1036         ADS_STRUCT *ads;
1037         ADS_STATUS rc;
1038         const char *servername;
1039         char *prt_dn;
1040         void *res = NULL;
1041
1042         if (!(ads = ads_startup())) {
1043                 return -1;
1044         }
1045
1046         if (argc < 1) {
1047                 return net_ads_printer_usage(argc, argv);
1048         }
1049
1050         if (argc > 1) {
1051                 servername = argv[1];
1052         } else {
1053                 servername = global_myname();
1054         }
1055
1056         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1057
1058         if (!ADS_ERR_OK(rc)) {
1059                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
1060                 ads_msgfree(ads, res);
1061                 ads_destroy(&ads);
1062                 return -1;
1063         }
1064
1065         if (ads_count_replies(ads, res) == 0) {
1066                 d_printf("Printer '%s' not found\n", argv[1]);
1067                 ads_msgfree(ads, res);
1068                 ads_destroy(&ads);
1069                 return -1;
1070         }
1071
1072         prt_dn = ads_get_dn(ads, res);
1073         ads_msgfree(ads, res);
1074         rc = ads_del_dn(ads, prt_dn);
1075         ads_memfree(ads, prt_dn);
1076
1077         if (!ADS_ERR_OK(rc)) {
1078                 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
1079                 ads_destroy(&ads);
1080                 return -1;
1081         }
1082
1083         ads_destroy(&ads);
1084         return 0;
1085 }
1086
1087 static int net_ads_printer(int argc, const char **argv)
1088 {
1089         struct functable func[] = {
1090                 {"SEARCH", net_ads_printer_search},
1091                 {"INFO", net_ads_printer_info},
1092                 {"PUBLISH", net_ads_printer_publish},
1093                 {"REMOVE", net_ads_printer_remove},
1094                 {NULL, NULL}
1095         };
1096         
1097         return net_run_function(argc, argv, func, net_ads_printer_usage);
1098 }
1099
1100
1101 static int net_ads_password(int argc, const char **argv)
1102 {
1103         ADS_STRUCT *ads;
1104         const char *auth_principal = opt_user_name;
1105         const char *auth_password = opt_password;
1106         char *realm = NULL;
1107         char *new_password = NULL;
1108         char *c, *prompt;
1109         const char *user;
1110         ADS_STATUS ret;
1111
1112         if (opt_user_name == NULL || opt_password == NULL) {
1113                 d_printf("You must supply an administrator username/password\n");
1114                 return -1;
1115         }
1116
1117         if (argc < 1) {
1118                 d_printf("ERROR: You must say which username to change password for\n");
1119                 return -1;
1120         }
1121
1122         user = argv[0];
1123         if (!strchr_m(user, '@')) {
1124                 asprintf(&c, "%s@%s", argv[0], lp_realm());
1125                 user = c;
1126         }
1127
1128         use_in_memory_ccache();    
1129         c = strchr(auth_principal, '@');
1130         if (c) {
1131                 realm = ++c;
1132         } else {
1133                 realm = lp_realm();
1134         }
1135
1136         /* use the realm so we can eventually change passwords for users 
1137         in realms other than default */
1138         if (!(ads = ads_init(realm, NULL, NULL))) {
1139                 return -1;
1140         }
1141
1142         /* we don't actually need a full connect, but it's the easy way to
1143                 fill in the KDC's addresss */
1144         ads_connect(ads);
1145     
1146         if (!ads || !ads->config.realm) {
1147                 d_printf("Didn't find the kerberos server!\n");
1148                 return -1;
1149         }
1150
1151         if (argv[1]) {
1152                 new_password = (char *)argv[1];
1153         } else {
1154                 asprintf(&prompt, "Enter new password for %s:", user);
1155                 new_password = getpass(prompt);
1156                 free(prompt);
1157         }
1158
1159         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
1160                                 auth_password, user, new_password, ads->auth.time_offset);
1161         if (!ADS_ERR_OK(ret)) {
1162                 d_printf("Password change failed :-( ...\n");
1163                 ads_destroy(&ads);
1164                 return -1;
1165         }
1166
1167         d_printf("Password change for %s completed.\n", user);
1168         ads_destroy(&ads);
1169
1170         return 0;
1171 }
1172
1173 int net_ads_changetrustpw(int argc, const char **argv)
1174 {    
1175         ADS_STRUCT *ads;
1176         char *host_principal;
1177         fstring my_name;
1178         ADS_STATUS ret;
1179
1180         if (!secrets_init()) {
1181                 DEBUG(1,("Failed to initialise secrets database\n"));
1182                 return -1;
1183         }
1184
1185         net_use_machine_password();
1186
1187         use_in_memory_ccache();
1188
1189         if (!(ads = ads_startup())) {
1190                 return -1;
1191         }
1192
1193         fstrcpy(my_name, global_myname());
1194         strlower_m(my_name);
1195         asprintf(&host_principal, "%s@%s", my_name, ads->config.realm);
1196         d_printf("Changing password for principal: HOST/%s\n", host_principal);
1197
1198         ret = ads_change_trust_account_password(ads, host_principal);
1199
1200         if (!ADS_ERR_OK(ret)) {
1201                 d_printf("Password change failed :-( ...\n");
1202                 ads_destroy(&ads);
1203                 SAFE_FREE(host_principal);
1204                 return -1;
1205         }
1206     
1207         d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1208
1209         if (lp_use_kerberos_keytab()) {
1210                 d_printf("Attempting to update system keytab with new password.\n");
1211                 if (ads_keytab_create_default(ads)) {
1212                         d_printf("Failed to update system keytab.\n");
1213                 }
1214         }
1215
1216         ads_destroy(&ads);
1217         SAFE_FREE(host_principal);
1218
1219         return 0;
1220 }
1221
1222 /*
1223   help for net ads search
1224 */
1225 static int net_ads_search_usage(int argc, const char **argv)
1226 {
1227         d_printf(
1228                 "\nnet ads search <expression> <attributes...>\n"\
1229                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1230                 "The expression is a standard LDAP search expression, and the\n"\
1231                 "attributes are a list of LDAP fields to show in the results\n\n"\
1232                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1233                 );
1234         net_common_flags_usage(argc, argv);
1235         return -1;
1236 }
1237
1238
1239 /*
1240   general ADS search function. Useful in diagnosing problems in ADS
1241 */
1242 static int net_ads_search(int argc, const char **argv)
1243 {
1244         ADS_STRUCT *ads;
1245         ADS_STATUS rc;
1246         const char *ldap_exp;
1247         const char **attrs;
1248         void *res = NULL;
1249
1250         if (argc < 1) {
1251                 return net_ads_search_usage(argc, argv);
1252         }
1253
1254         if (!(ads = ads_startup())) {
1255                 return -1;
1256         }
1257
1258         ldap_exp = argv[0];
1259         attrs = (argv + 1);
1260
1261         rc = ads_do_search_all(ads, ads->config.bind_path,
1262                                LDAP_SCOPE_SUBTREE,
1263                                ldap_exp, attrs, &res);
1264         if (!ADS_ERR_OK(rc)) {
1265                 d_printf("search failed: %s\n", ads_errstr(rc));
1266                 ads_destroy(&ads);
1267                 return -1;
1268         }       
1269
1270         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1271
1272         /* dump the results */
1273         ads_dump(ads, res);
1274
1275         ads_msgfree(ads, res);
1276         ads_destroy(&ads);
1277
1278         return 0;
1279 }
1280
1281
1282 /*
1283   help for net ads search
1284 */
1285 static int net_ads_dn_usage(int argc, const char **argv)
1286 {
1287         d_printf(
1288                 "\nnet ads dn <dn> <attributes...>\n"\
1289                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1290                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1291                 "to show in the results\n\n"\
1292                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1293                 );
1294         net_common_flags_usage(argc, argv);
1295         return -1;
1296 }
1297
1298
1299 /*
1300   general ADS search function. Useful in diagnosing problems in ADS
1301 */
1302 static int net_ads_dn(int argc, const char **argv)
1303 {
1304         ADS_STRUCT *ads;
1305         ADS_STATUS rc;
1306         const char *dn;
1307         const char **attrs;
1308         void *res = NULL;
1309
1310         if (argc < 1) {
1311                 return net_ads_dn_usage(argc, argv);
1312         }
1313
1314         if (!(ads = ads_startup())) {
1315                 return -1;
1316         }
1317
1318         dn = argv[0];
1319         attrs = (argv + 1);
1320
1321         rc = ads_do_search_all(ads, dn, 
1322                                LDAP_SCOPE_BASE,
1323                                "(objectclass=*)", attrs, &res);
1324         if (!ADS_ERR_OK(rc)) {
1325                 d_printf("search failed: %s\n", ads_errstr(rc));
1326                 ads_destroy(&ads);
1327                 return -1;
1328         }       
1329
1330         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1331
1332         /* dump the results */
1333         ads_dump(ads, res);
1334
1335         ads_msgfree(ads, res);
1336         ads_destroy(&ads);
1337
1338         return 0;
1339 }
1340
1341 static int net_ads_keytab_usage(int argc, const char **argv)
1342 {
1343         d_printf(
1344                 "net ads keytab <COMMAND>\n"\
1345 "<COMMAND> can be either:\n"\
1346 "  CREATE    Creates a fresh keytab\n"\
1347 "  ADD       Adds new service principal\n"\
1348 "  FLUSH     Flushes out all keytab entries\n"\
1349 "  HELP      Prints this help message\n"\
1350 "The ADD command will take arguments, the other commands\n"\
1351 "will not take any arguments.   The arguments given to ADD\n"\
1352 "should be a list of principals to add.  For example, \n"\
1353 "   net ads keytab add srv1 srv2\n"\
1354 "will add principals for the services srv1 and srv2 to the\n"\
1355 "system's keytab.\n"\
1356 "\n"
1357                 );
1358         return -1;
1359 }
1360
1361 static int net_ads_keytab_flush(int argc, const char **argv)
1362 {
1363         int ret;
1364         ADS_STRUCT *ads;
1365
1366         if (!(ads = ads_startup())) {
1367                 return -1;
1368         }
1369         ret = ads_keytab_flush(ads);
1370         ads_destroy(&ads);
1371         return ret;
1372 }
1373
1374 static int net_ads_keytab_add(int argc, const char **argv)
1375 {
1376         int i;
1377         int ret = 0;
1378         ADS_STRUCT *ads;
1379
1380         d_printf("Processing principals to add...\n");
1381         if (!(ads = ads_startup())) {
1382                 return -1;
1383         }
1384         for (i = 0; i < argc; i++) {
1385                 ret |= ads_keytab_add_entry(ads, argv[i]);
1386         }
1387         ads_destroy(&ads);
1388         return ret;
1389 }
1390
1391 static int net_ads_keytab_create(int argc, const char **argv)
1392 {
1393         ADS_STRUCT *ads;
1394         int ret;
1395
1396         if (!(ads = ads_startup())) {
1397                 return -1;
1398         }
1399         ret = ads_keytab_create_default(ads);
1400         ads_destroy(&ads);
1401         return ret;
1402 }
1403
1404 int net_ads_keytab(int argc, const char **argv)
1405 {
1406         struct functable func[] = {
1407                 {"CREATE", net_ads_keytab_create},
1408                 {"ADD", net_ads_keytab_add},
1409                 {"FLUSH", net_ads_keytab_flush},
1410                 {"HELP", net_ads_keytab_usage},
1411                 {NULL, NULL}
1412         };
1413
1414         if (!lp_use_kerberos_keytab()) {
1415                 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
1416 use keytab functions.\n");
1417         }
1418
1419         return net_run_function(argc, argv, func, net_ads_keytab_usage);
1420 }
1421
1422 int net_ads_help(int argc, const char **argv)
1423 {
1424         struct functable func[] = {
1425                 {"USER", net_ads_user_usage},
1426                 {"GROUP", net_ads_group_usage},
1427                 {"PRINTER", net_ads_printer_usage},
1428                 {"SEARCH", net_ads_search_usage},
1429 #if 0
1430                 {"INFO", net_ads_info},
1431                 {"JOIN", net_ads_join},
1432                 {"LEAVE", net_ads_leave},
1433                 {"STATUS", net_ads_status},
1434                 {"PASSWORD", net_ads_password},
1435                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1436 #endif
1437                 {NULL, NULL}
1438         };
1439
1440         return net_run_function(argc, argv, func, net_ads_usage);
1441 }
1442
1443 int net_ads(int argc, const char **argv)
1444 {
1445         struct functable func[] = {
1446                 {"INFO", net_ads_info},
1447                 {"JOIN", net_ads_join},
1448                 {"TESTJOIN", net_ads_testjoin},
1449                 {"LEAVE", net_ads_leave},
1450                 {"STATUS", net_ads_status},
1451                 {"USER", net_ads_user},
1452                 {"GROUP", net_ads_group},
1453                 {"PASSWORD", net_ads_password},
1454                 {"CHANGETRUSTPW", net_ads_changetrustpw},
1455                 {"PRINTER", net_ads_printer},
1456                 {"SEARCH", net_ads_search},
1457                 {"DN", net_ads_dn},
1458                 {"WORKGROUP", net_ads_workgroup},
1459                 {"LOOKUP", net_ads_lookup},
1460                 {"KEYTAB", net_ads_keytab},
1461                 {"HELP", net_ads_help},
1462                 {NULL, NULL}
1463         };
1464         
1465         return net_run_function(argc, argv, func, net_ads_usage);
1466 }
1467
1468 #else
1469
1470 static int net_ads_noads(void)
1471 {
1472         d_printf("ADS support not compiled in\n");
1473         return -1;
1474 }
1475
1476 int net_ads_keytab(int argc, const char **argv)
1477 {
1478         return net_ads_noads();
1479 }
1480
1481 int net_ads_usage(int argc, const char **argv)
1482 {
1483         return net_ads_noads();
1484 }
1485
1486 int net_ads_help(int argc, const char **argv)
1487 {
1488         return net_ads_noads();
1489 }
1490
1491 int net_ads_changetrustpw(int argc, const char **argv)
1492 {
1493         return net_ads_noads();
1494 }
1495
1496 int net_ads_join(int argc, const char **argv)
1497 {
1498         return net_ads_noads();
1499 }
1500
1501 int net_ads_user(int argc, const char **argv)
1502 {
1503         return net_ads_noads();
1504 }
1505
1506 int net_ads_group(int argc, const char **argv)
1507 {
1508         return net_ads_noads();
1509 }
1510
1511 /* this one shouldn't display a message */
1512 int net_ads_check(void)
1513 {
1514         return -1;
1515 }
1516
1517 int net_ads(int argc, const char **argv)
1518 {
1519         return net_ads_usage(argc, argv);
1520 }
1521
1522 #endif