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