This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[jra/samba/.git] / source3 / utils / net_ads.c
1 /* 
2    Samba Unix/Linux SMB client library 
3    net ads commands
4    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
21 */
22
23 #include "includes.h"
24 #include "../utils/net.h"
25
26 #ifdef HAVE_ADS
27
28 int net_ads_usage(int argc, const char **argv)
29 {
30         d_printf(
31 "\nnet ads join <org_unit>"\
32 "\n\tjoins the local machine to a ADS realm\n"\
33 "\nnet ads leave"\
34 "\n\tremoves the local machine from a ADS realm\n"\
35 "\nnet ads testjoin"\
36 "\n\ttests that an exiting join is OK\n"\
37 "\nnet ads user"\
38 "\n\tlist, add, or delete users in the realm\n"\
39 "\nnet ads group"\
40 "\n\tlist, add, or delete groups in the realm\n"\
41 "\nnet ads info"\
42 "\n\tshows some info on the server\n"\
43 "\nnet ads status"\
44 "\n\tdump the machine account details to stdout\n"
45 "\nnet ads password <username@realm> -Uadmin_username@realm%%admin_pass"\
46 "\n\tchange a user's password using an admin account"\
47 "\n\t(note: use realm in UPPERCASE)\n"\
48 "\nnet ads chostpass"\
49 "\n\tchange the trust account password of this machine in the AD tree\n"\
50 "\nnet ads printer [info | publish | remove] <printername> <servername>"\
51 "\n\t lookup, add, or remove directory entry for a printer\n"\
52 "\nnet ads search"\
53 "\n\tperform a raw LDAP search and dump the results\n"
54                 );
55         return -1;
56 }
57
58
59 /*
60   this implements the CLDAP based netlogon lookup requests
61   for finding the domain controller of a ADS domain
62 */
63 static int net_ads_lookup(int argc, const char **argv)
64 {
65         ADS_STRUCT *ads;
66
67         ads = ads_init(NULL, NULL, opt_host);
68         if (ads) {
69                 ads->auth.flags |= ADS_AUTH_NO_BIND;
70         }
71
72         ads_connect(ads);
73
74         if (!ads || !ads->config.realm) {
75                 d_printf("Didn't find the cldap server!\n");
76                 return -1;
77         }
78
79         return ads_cldap_netlogon(ads);
80 }
81
82
83
84 static int net_ads_info(int argc, const char **argv)
85 {
86         ADS_STRUCT *ads;
87
88         ads = ads_init(NULL, NULL, opt_host);
89
90         if (ads) {
91                 ads->auth.flags |= ADS_AUTH_NO_BIND;
92         }
93
94         ads_connect(ads);
95
96         if (!ads || !ads->config.realm) {
97                 d_printf("Didn't find the ldap server!\n");
98                 return -1;
99         }
100
101         d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
102         d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
103         d_printf("Realm: %s\n", ads->config.realm);
104         d_printf("Bind Path: %s\n", ads->config.bind_path);
105         d_printf("LDAP port: %d\n", ads->ldap_port);
106         d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
107
108         return 0;
109 }
110
111
112 static ADS_STRUCT *ads_startup(void)
113 {
114         ADS_STRUCT *ads;
115         ADS_STATUS status;
116         BOOL need_password = False;
117         BOOL second_time = False;
118         
119         ads = ads_init(NULL, NULL, opt_host);
120
121         if (!opt_user_name) {
122                 opt_user_name = "administrator";
123         }
124
125         if (opt_user_specified)
126                 need_password = True;
127
128 retry:
129         if (!opt_password && need_password) {
130                 char *prompt;
131                 asprintf(&prompt,"%s password: ", opt_user_name);
132                 opt_password = getpass(prompt);
133                 free(prompt);
134         }
135
136         if (opt_password)
137                 ads->auth.password = strdup(opt_password);
138
139         ads->auth.user_name = strdup(opt_user_name);
140
141         status = ads_connect(ads);
142         if (!ADS_ERR_OK(status)) {
143                 if (!need_password && !second_time) {
144                         need_password = True;
145                         second_time = True;
146                         goto retry;
147                 } else {
148                         DEBUG(1,("ads_connect: %s\n", ads_errstr(status)));
149                         return NULL;
150                 }
151         }
152         return ads;
153 }
154
155
156 /*
157   Check to see if connection can be made via ads.
158   ads_startup() stores the password in opt_password if it needs to so
159   that rpc or rap can use it without re-prompting.
160 */
161 int net_ads_check(void)
162 {
163         ADS_STRUCT *ads;
164
165         ads = ads_startup();
166         if (!ads)
167                 return -1;
168         ads_destroy(&ads);
169         return 0;
170 }
171
172 /* 
173    determine the netbios workgroup name for a domain
174  */
175 static int net_ads_workgroup(int argc, const char **argv)
176 {
177         ADS_STRUCT *ads;
178         TALLOC_CTX *ctx;
179         char *workgroup;
180
181         if (!(ads = ads_startup())) return -1;
182
183         if (!(ctx = talloc_init("net_ads_workgroup"))) {
184                 return -1;
185         }
186
187         if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
188                 d_printf("Failed to find workgroup for realm '%s'\n", 
189                          ads->config.realm);
190                 talloc_destroy(ctx);
191                 return -1;
192         }
193
194         d_printf("Workgroup: %s\n", workgroup);
195
196         talloc_destroy(ctx);
197
198         return 0;
199 }
200
201
202
203 static BOOL usergrp_display(char *field, void **values, void *data_area)
204 {
205         char **disp_fields = (char **) data_area;
206
207         if (!field) { /* must be end of record */
208                 if (!strchr_m(disp_fields[0], '$')) {
209                         if (disp_fields[1])
210                                 d_printf("%-21.21s %-50.50s\n", 
211                                        disp_fields[0], disp_fields[1]);
212                         else
213                                 d_printf("%s\n", disp_fields[0]);
214                 }
215                 SAFE_FREE(disp_fields[0]);
216                 SAFE_FREE(disp_fields[1]);
217                 return True;
218         }
219         if (!values) /* must be new field, indicate string field */
220                 return True;
221         if (StrCaseCmp(field, "sAMAccountName") == 0) {
222                 disp_fields[0] = strdup((char *) values[0]);
223         }
224         if (StrCaseCmp(field, "description") == 0)
225                 disp_fields[1] = strdup((char *) values[0]);
226         return True;
227 }
228
229 static int net_ads_user_usage(int argc, const char **argv)
230 {
231         return net_help_user(argc, argv);
232
233
234 static int ads_user_add(int argc, const char **argv)
235 {
236         ADS_STRUCT *ads;
237         ADS_STATUS status;
238         char *upn, *userdn;
239         void *res=NULL;
240         int rc = -1;
241
242         if (argc < 1) return net_ads_user_usage(argc, argv);
243         
244         if (!(ads = ads_startup())) return -1;
245
246         status = ads_find_user_acct(ads, &res, argv[0]);
247
248         if (!ADS_ERR_OK(status)) {
249                 d_printf("ads_user_add: %s\n", ads_errstr(status));
250                 goto done;
251         }
252         
253         if (ads_count_replies(ads, res)) {
254                 d_printf("ads_user_add: User %s already exists\n", argv[0]);
255                 goto done;
256         }
257
258         status = ads_add_user_acct(ads, argv[0], opt_comment);
259
260         if (!ADS_ERR_OK(status)) {
261                 d_printf("Could not add user %s: %s\n", argv[0],
262                          ads_errstr(status));
263                 goto done;
264         }
265
266         /* if no password is to be set, we're done */
267         if (argc == 1) { 
268                 d_printf("User %s added\n", argv[0]);
269                 rc = 0;
270                 goto done;
271         }
272
273         /* try setting the password */
274         asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
275         status = krb5_set_password(ads->auth.kdc_server, upn, argv[1], ads->auth.time_offset);
276         safe_free(upn);
277         if (ADS_ERR_OK(status)) {
278                 d_printf("User %s added\n", argv[0]);
279                 rc = 0;
280                 goto done;
281         }
282
283         /* password didn't set, delete account */
284         d_printf("Could not add user %s.  Error setting password %s\n",
285                  argv[0], ads_errstr(status));
286         ads_msgfree(ads, res);
287         status=ads_find_user_acct(ads, &res, argv[0]);
288         if (ADS_ERR_OK(status)) {
289                 userdn = ads_get_dn(ads, res);
290                 ads_del_dn(ads, userdn);
291                 ads_memfree(ads, userdn);
292         }
293
294  done:
295         if (res)
296                 ads_msgfree(ads, res);
297         ads_destroy(&ads);
298         return rc;
299 }
300
301 static int ads_user_info(int argc, const char **argv)
302 {
303         ADS_STRUCT *ads;
304         ADS_STATUS rc;
305         void *res;
306         const char *attrs[] = {"memberOf", NULL};
307         char *searchstring=NULL;
308         char **grouplist;
309
310         if (argc < 1) return net_ads_user_usage(argc, argv);
311         
312         if (!(ads = ads_startup())) return -1;
313
314         asprintf(&searchstring, "(sAMAccountName=%s)", argv[0]);
315         rc = ads_search(ads, &res, searchstring, attrs);
316         safe_free(searchstring);
317
318         if (!ADS_ERR_OK(rc)) {
319                 d_printf("ads_search: %s\n", ads_errstr(rc));
320                 return -1;
321         }
322         
323         grouplist = ldap_get_values(ads->ld, res, "memberOf");
324
325         if (grouplist) {
326                 int i;
327                 char **groupname;
328                 for (i=0;grouplist[i];i++) {
329                         groupname = ldap_explode_dn(grouplist[i], 1);
330                         d_printf("%s\n", groupname[0]);
331                         ldap_value_free(groupname);
332                 }
333                 ldap_value_free(grouplist);
334         }
335         
336         ads_msgfree(ads, res);
337
338         ads_destroy(&ads);
339         return 0;
340 }
341
342 static int ads_user_delete(int argc, const char **argv)
343 {
344         ADS_STRUCT *ads;
345         ADS_STATUS rc;
346         void *res;
347         char *userdn;
348
349         if (argc < 1) return net_ads_user_usage(argc, argv);
350         
351         if (!(ads = ads_startup())) return -1;
352
353         rc = ads_find_user_acct(ads, &res, argv[0]);
354         if (!ADS_ERR_OK(rc)) {
355                 DEBUG(0, ("User %s does not exist\n", argv[0]));
356                 return -1;
357         }
358         userdn = ads_get_dn(ads, res);
359         ads_msgfree(ads, res);
360         rc = ads_del_dn(ads, userdn);
361         ads_memfree(ads, userdn);
362         if (!ADS_ERR_OK(rc)) {
363                 d_printf("User %s deleted\n", argv[0]);
364                 return 0;
365         }
366         d_printf("Error deleting user %s: %s\n", argv[0], 
367                  ads_errstr(rc));
368         return -1;
369 }
370
371 int net_ads_user(int argc, const char **argv)
372 {
373         struct functable func[] = {
374                 {"ADD", ads_user_add},
375                 {"INFO", ads_user_info},
376                 {"DELETE", ads_user_delete},
377                 {NULL, NULL}
378         };
379         ADS_STRUCT *ads;
380         ADS_STATUS rc;
381         const char *shortattrs[] = {"sAMAccountName", NULL};
382         const char *longattrs[] = {"sAMAccountName", "description", NULL};
383         char *disp_fields[2] = {NULL, NULL};
384         
385         if (argc == 0) {
386                 if (!(ads = ads_startup())) return -1;
387
388                 if (opt_long_list_entries)
389                         d_printf("\nUser name             Comment"\
390                                  "\n-----------------------------\n");
391
392                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
393                                           LDAP_SCOPE_SUBTREE,
394                                           "(objectclass=user)", 
395                                           opt_long_list_entries ? longattrs :
396                                           shortattrs, usergrp_display, 
397                                           disp_fields);
398                 ads_destroy(&ads);
399                 return 0;
400         }
401
402         return net_run_function(argc, argv, func, net_ads_user_usage);
403 }
404
405 static int net_ads_group_usage(int argc, const char **argv)
406 {
407         return net_help_group(argc, argv);
408
409
410 static int ads_group_add(int argc, const char **argv)
411 {
412         ADS_STRUCT *ads;
413         ADS_STATUS status;
414         void *res=NULL;
415         int rc = -1;
416
417         if (argc < 1) return net_ads_group_usage(argc, argv);
418         
419         if (!(ads = ads_startup())) return -1;
420
421         status = ads_find_user_acct(ads, &res, argv[0]);
422
423         if (!ADS_ERR_OK(status)) {
424                 d_printf("ads_group_add: %s\n", ads_errstr(status));
425                 goto done;
426         }
427         
428         if (ads_count_replies(ads, res)) {
429                 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
430                 ads_msgfree(ads, res);
431                 goto done;
432         }
433
434         status = ads_add_group_acct(ads, argv[0], opt_comment);
435
436         if (ADS_ERR_OK(status)) {
437                 d_printf("Group %s added\n", argv[0]);
438                 rc = 0;
439         } else {
440                 d_printf("Could not add group %s: %s\n", argv[0],
441                          ads_errstr(status));
442         }
443
444  done:
445         if (res)
446                 ads_msgfree(ads, res);
447         ads_destroy(&ads);
448         return rc;
449 }
450
451 static int ads_group_delete(int argc, const char **argv)
452 {
453         ADS_STRUCT *ads;
454         ADS_STATUS rc;
455         void *res;
456         char *groupdn;
457
458         if (argc < 1) return net_ads_group_usage(argc, argv);
459         
460         if (!(ads = ads_startup())) return -1;
461
462         rc = ads_find_user_acct(ads, &res, argv[0]);
463         if (!ADS_ERR_OK(rc)) {
464                 DEBUG(0, ("Group %s does not exist\n", argv[0]));
465                 return -1;
466         }
467         groupdn = ads_get_dn(ads, res);
468         ads_msgfree(ads, res);
469         rc = ads_del_dn(ads, groupdn);
470         ads_memfree(ads, groupdn);
471         if (!ADS_ERR_OK(rc)) {
472                 d_printf("Group %s deleted\n", argv[0]);
473                 return 0;
474         }
475         d_printf("Error deleting group %s: %s\n", argv[0], 
476                  ads_errstr(rc));
477         return -1;
478 }
479
480 int net_ads_group(int argc, const char **argv)
481 {
482         struct functable func[] = {
483                 {"ADD", ads_group_add},
484                 {"DELETE", ads_group_delete},
485                 {NULL, NULL}
486         };
487         ADS_STRUCT *ads;
488         ADS_STATUS rc;
489         const char *shortattrs[] = {"sAMAccountName", NULL};
490         const char *longattrs[] = {"sAMAccountName", "description", NULL};
491         char *disp_fields[2] = {NULL, NULL};
492
493         if (argc == 0) {
494                 if (!(ads = ads_startup())) return -1;
495
496                 if (opt_long_list_entries)
497                         d_printf("\nGroup name            Comment"\
498                                  "\n-----------------------------\n");
499                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
500                                           LDAP_SCOPE_SUBTREE, 
501                                           "(objectclass=group)", 
502                                           opt_long_list_entries ? longattrs : 
503                                           shortattrs, usergrp_display, 
504                                           disp_fields);
505
506                 ads_destroy(&ads);
507                 return 0;
508         }
509         return net_run_function(argc, argv, func, net_ads_group_usage);
510 }
511
512 static int net_ads_status(int argc, const char **argv)
513 {
514         ADS_STRUCT *ads;
515         ADS_STATUS rc;
516         void *res;
517
518         if (!(ads = ads_startup())) return -1;
519
520         rc = ads_find_machine_acct(ads, &res, global_myname());
521         if (!ADS_ERR_OK(rc)) {
522                 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
523                 return -1;
524         }
525
526         if (ads_count_replies(ads, res) == 0) {
527                 d_printf("No machine account for '%s' found\n", global_myname());
528                 return -1;
529         }
530
531         ads_dump(ads, res);
532
533         return 0;
534 }
535
536 static int net_ads_leave(int argc, const char **argv)
537 {
538         ADS_STRUCT *ads = NULL;
539         ADS_STATUS rc;
540
541         if (!secrets_init()) {
542                 DEBUG(1,("Failed to initialise secrets database\n"));
543                 return -1;
544         }
545
546         if (!opt_password) {
547                 asprintf(&opt_user_name, "%s$", global_myname());
548                 opt_password = secrets_fetch_machine_password();
549         }
550
551         if (!(ads = ads_startup())) {
552                 return -1;
553         }
554
555         rc = ads_leave_realm(ads, global_myname());
556         if (!ADS_ERR_OK(rc)) {
557             d_printf("Failed to delete host '%s' from the '%s' realm.\n", 
558                      global_myname(), ads->config.realm);
559             return -1;
560         }
561
562         d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
563
564         return 0;
565 }
566
567 static int net_ads_join_ok(void)
568 {
569         ADS_STRUCT *ads = NULL;
570
571         if (!secrets_init()) {
572                 DEBUG(1,("Failed to initialise secrets database\n"));
573                 return -1;
574         }
575
576         asprintf(&opt_user_name, "%s$", global_myname());
577         opt_password = secrets_fetch_machine_password();
578
579         if (!(ads = ads_startup())) {
580                 return -1;
581         }
582
583         ads_destroy(&ads);
584         return 0;
585 }
586
587 /*
588   check that an existing join is OK
589  */
590 int net_ads_testjoin(int argc, const char **argv)
591 {
592         /* Display success or failure */
593         if (net_ads_join_ok() != 0) {
594                 fprintf(stderr,"Join to domain is not valid\n");
595                 return -1;
596         }
597
598         printf("Join is OK\n");
599         return 0;
600 }
601
602 /*
603   join a domain using ADS
604  */
605 int net_ads_join(int argc, const char **argv)
606 {
607         ADS_STRUCT *ads;
608         ADS_STATUS rc;
609         char *password;
610         char *tmp_password;
611         const char *org_unit = "Computers";
612         char *dn;
613         void *res;
614         DOM_SID dom_sid;
615         char *ou_str;
616
617         if (argc > 0) org_unit = argv[0];
618
619         if (!secrets_init()) {
620                 DEBUG(1,("Failed to initialise secrets database\n"));
621                 return -1;
622         }
623
624         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
625         password = strdup(tmp_password);
626
627         if (!(ads = ads_startup())) return -1;
628
629         ou_str = ads_ou_string(org_unit);
630         asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
631         free(ou_str);
632
633         rc = ads_search_dn(ads, &res, dn, NULL);
634         ads_msgfree(ads, res);
635
636         if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
637                 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", 
638                          org_unit, dn);
639                 return -1;
640         }
641         free(dn);
642
643         if (!ADS_ERR_OK(rc)) {
644                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
645                 return -1;
646         }       
647
648         rc = ads_join_realm(ads, global_myname(), org_unit);
649         if (!ADS_ERR_OK(rc)) {
650                 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
651                 return -1;
652         }
653
654         rc = ads_domain_sid(ads, &dom_sid);
655         if (!ADS_ERR_OK(rc)) {
656                 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
657                 return -1;
658         }
659
660         rc = ads_set_machine_password(ads, global_myname(), password);
661         if (!ADS_ERR_OK(rc)) {
662                 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
663                 return -1;
664         }
665
666         if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
667                 DEBUG(1,("Failed to save domain sid\n"));
668                 return -1;
669         }
670
671         if (!secrets_store_machine_password(password)) {
672                 DEBUG(1,("Failed to save machine password\n"));
673                 return -1;
674         }
675
676         d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
677
678         free(password);
679
680         return 0;
681 }
682
683 int net_ads_printer_usage(int argc, const char **argv)
684 {
685         d_printf(
686 "\nnet ads printer info <printer> <server>"
687 "\n\tlookup info in directory for printer on server"
688 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
689 "\nnet ads printer publish <printername>"
690 "\n\tpublish printer in directory"
691 "\n\t(note: printer name is required)\n"
692 "\nnet ads printer remove <printername>"
693 "\n\tremove printer from directory"
694 "\n\t(note: printer name is required)\n");
695         return -1;
696 }
697
698 static int net_ads_printer_info(int argc, const char **argv)
699 {
700         ADS_STRUCT *ads;
701         ADS_STATUS rc;
702         const char *servername, *printername;
703         void *res = NULL;
704
705         if (!(ads = ads_startup())) return -1;
706
707         if (argc > 0)
708                 printername = argv[0];
709         else
710                 printername = "*";
711
712         if (argc > 1)
713                 servername =  argv[1];
714         else
715                 servername = global_myname();
716
717         rc = ads_find_printer_on_server(ads, &res, printername, servername);
718
719         if (!ADS_ERR_OK(rc)) {
720                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
721                 ads_msgfree(ads, res);
722                 return -1;
723         }
724
725         if (ads_count_replies(ads, res) == 0) {
726                 d_printf("Printer '%s' not found\n", printername);
727                 ads_msgfree(ads, res);
728                 return -1;
729         }
730
731         ads_dump(ads, res);
732         ads_msgfree(ads, res);
733
734         return 0;
735 }
736
737 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
738 {
739         return;
740 }
741
742 static int net_ads_printer_publish(int argc, const char **argv)
743 {
744         ADS_STRUCT *ads;
745         ADS_STATUS rc;
746         char *servername;
747         struct cli_state *cli;
748         struct in_addr          server_ip;
749         NTSTATUS nt_status;
750         extern char *opt_workgroup;
751         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
752         ADS_MODLIST mods = ads_init_mods(mem_ctx);
753         char *prt_dn, *srv_dn, **srv_cn;
754         void *res = NULL;
755
756         if (!(ads = ads_startup())) return -1;
757
758         if (argc < 1)
759                 return net_ads_printer_usage(argc, argv);
760         
761         if (argc == 2)
762                 servername = argv[1];
763         else
764                 servername = global_myname();
765                 
766         ads_find_machine_acct(ads, &res, servername);
767         srv_dn = ldap_get_dn(ads->ld, res);
768         srv_cn = ldap_explode_dn(srv_dn, 1);
769         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], argv[0], srv_dn);
770
771         resolve_name(servername, &server_ip, 0x20);
772
773         nt_status = cli_full_connection(&cli, global_myname(), servername, 
774                                         &server_ip, 0,
775                                         "IPC$", "IPC",  
776                                         opt_user_name, opt_workgroup,
777                                         opt_password ? opt_password : "", 
778                                         CLI_FULL_CONNECTION_USE_KERBEROS, 
779                                         NULL);
780
781         cli_nt_session_open(cli, PI_SPOOLSS);
782         get_remote_printer_publishing_data(cli, mem_ctx, &mods, argv[0]);
783
784         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
785         if (!ADS_ERR_OK(rc)) {
786                 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
787                 return -1;
788         }
789  
790         d_printf("published printer\n");
791  
792         return 0;
793 }
794
795 static int net_ads_printer_remove(int argc, const char **argv)
796 {
797         ADS_STRUCT *ads;
798         ADS_STATUS rc;
799         const char *servername;
800         char *prt_dn;
801         void *res = NULL;
802
803         if (!(ads = ads_startup())) return -1;
804
805         if (argc < 1)
806                 return net_ads_printer_usage(argc, argv);
807
808         if (argc > 1)
809                 servername = argv[1];
810         else
811                 servername = global_myname();
812
813         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
814
815         if (!ADS_ERR_OK(rc)) {
816                 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
817                 ads_msgfree(ads, res);
818                 return -1;
819         }
820
821         if (ads_count_replies(ads, res) == 0) {
822                 d_printf("Printer '%s' not found\n", argv[1]);
823                 ads_msgfree(ads, res);
824                 return -1;
825         }
826
827         prt_dn = ads_get_dn(ads, res);
828         ads_msgfree(ads, res);
829         rc = ads_del_dn(ads, prt_dn);
830         ads_memfree(ads, prt_dn);
831
832         if (!ADS_ERR_OK(rc)) {
833                 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
834                 return -1;
835         }
836
837         return 0;
838 }
839
840 static int net_ads_printer(int argc, const char **argv)
841 {
842         struct functable func[] = {
843                 {"INFO", net_ads_printer_info},
844                 {"PUBLISH", net_ads_printer_publish},
845                 {"REMOVE", net_ads_printer_remove},
846                 {NULL, NULL}
847         };
848         
849         return net_run_function(argc, argv, func, net_ads_printer_usage);
850 }
851
852
853 static int net_ads_password(int argc, const char **argv)
854 {
855     ADS_STRUCT *ads;
856     char *auth_principal = opt_user_name;
857     char *auth_password = opt_password;
858     char *realm = NULL;
859     char *new_password = NULL;
860     char *c;
861     char *prompt;
862     ADS_STATUS ret;
863
864     
865     if ((argc != 1) || (opt_user_name == NULL) || 
866         (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
867         (strchr(argv[0], '@') == NULL)) {
868         return net_ads_usage(argc, argv);
869     }
870     
871     c = strchr(auth_principal, '@');
872     realm = ++c;
873
874     /* use the realm so we can eventually change passwords for users 
875     in realms other than default */
876     if (!(ads = ads_init(realm, NULL, NULL))) return -1;
877
878     asprintf(&prompt, "Enter new password for %s:", argv[0]);
879
880     new_password = getpass(prompt);
881
882     ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
883                                 auth_password, argv[0], new_password, ads->auth.time_offset);
884     if (!ADS_ERR_OK(ret)) {
885         d_printf("Password change failed :-( ...\n");
886         ads_destroy(&ads);
887         free(prompt);
888         return -1;
889     }
890
891     d_printf("Password change for %s completed.\n", argv[0]);
892     ads_destroy(&ads);
893     free(prompt);
894
895     return 0;
896 }
897
898
899 static int net_ads_change_localhost_pass(int argc, const char **argv)
900 {    
901     ADS_STRUCT *ads;
902     char *host_principal;
903     char *hostname;
904     ADS_STATUS ret;
905
906     if (!secrets_init()) {
907             DEBUG(1,("Failed to initialise secrets database\n"));
908             return -1;
909     }
910
911     asprintf(&opt_user_name, "%s$", global_myname());
912     opt_password = secrets_fetch_machine_password();
913
914     if (!(ads = ads_startup())) {
915             return -1;
916     }
917
918     hostname = strdup(global_myname());
919     strlower(hostname);
920     asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
921     SAFE_FREE(hostname);
922     d_printf("Changing password for principal: HOST/%s\n", host_principal);
923     
924     ret = ads_change_trust_account_password(ads, host_principal);
925
926     if (!ADS_ERR_OK(ret)) {
927         d_printf("Password change failed :-( ...\n");
928         ads_destroy(&ads);
929         SAFE_FREE(host_principal);
930         return -1;
931     }
932     
933     d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
934     ads_destroy(&ads);
935     SAFE_FREE(host_principal);
936
937     return 0;
938 }
939
940 /*
941   help for net ads search
942 */
943 static int net_ads_search_usage(int argc, const char **argv)
944 {
945         d_printf(
946                 "\nnet ads search <expression> <attributes...>\n"\
947                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
948                 "The expression is a standard LDAP search expression, and the\n"\
949                 "attributes are a list of LDAP fields to show in the results\n\n"\
950                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
951                 );
952         net_common_flags_usage(argc, argv);
953         return -1;
954 }
955
956
957 /*
958   general ADS search function. Useful in diagnosing problems in ADS
959 */
960 static int net_ads_search(int argc, const char **argv)
961 {
962         ADS_STRUCT *ads;
963         ADS_STATUS rc;
964         const char *exp;
965         const char **attrs;
966         void *res = NULL;
967
968         if (argc < 1) {
969                 return net_ads_search_usage(argc, argv);
970         }
971
972         if (!(ads = ads_startup())) {
973                 return -1;
974         }
975
976         exp = argv[0];
977         attrs = (argv + 1);
978
979         rc = ads_do_search_all(ads, ads->config.bind_path, 
980                                LDAP_SCOPE_SUBTREE,
981                                exp, attrs, &res);
982         if (!ADS_ERR_OK(rc)) {
983                 d_printf("search failed: %s\n", ads_errstr(rc));
984                 return -1;
985         }       
986
987         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
988
989         /* dump the results */
990         ads_dump(ads, res);
991
992         ads_msgfree(ads, res);
993         ads_destroy(&ads);
994
995         return 0;
996 }
997
998
999 int net_ads_help(int argc, const char **argv)
1000 {
1001         struct functable func[] = {
1002                 {"USER", net_ads_user_usage},
1003                 {"GROUP", net_ads_group_usage},
1004                 {"PRINTER", net_ads_printer_usage},
1005                 {"SEARCH", net_ads_search_usage},
1006 #if 0
1007                 {"INFO", net_ads_info},
1008                 {"JOIN", net_ads_join},
1009                 {"LEAVE", net_ads_leave},
1010                 {"STATUS", net_ads_status},
1011                 {"PASSWORD", net_ads_password},
1012                 {"CHOSTPASS", net_ads_change_localhost_pass},
1013 #endif
1014                 {NULL, NULL}
1015         };
1016
1017         return net_run_function(argc, argv, func, net_ads_usage);
1018 }
1019
1020 int net_ads(int argc, const char **argv)
1021 {
1022         struct functable func[] = {
1023                 {"INFO", net_ads_info},
1024                 {"JOIN", net_ads_join},
1025                 {"TESTJOIN", net_ads_testjoin},
1026                 {"LEAVE", net_ads_leave},
1027                 {"STATUS", net_ads_status},
1028                 {"USER", net_ads_user},
1029                 {"GROUP", net_ads_group},
1030                 {"PASSWORD", net_ads_password},
1031                 {"CHOSTPASS", net_ads_change_localhost_pass},
1032                 {"PRINTER", net_ads_printer},
1033                 {"SEARCH", net_ads_search},
1034                 {"WORKGROUP", net_ads_workgroup},
1035                 {"LOOKUP", net_ads_lookup},
1036                 {"HELP", net_ads_help},
1037                 {NULL, NULL}
1038         };
1039         
1040         return net_run_function(argc, argv, func, net_ads_usage);
1041 }
1042
1043 #else
1044
1045 static int net_ads_noads(void)
1046 {
1047         d_printf("ADS support not compiled in\n");
1048         return -1;
1049 }
1050
1051 int net_ads_usage(int argc, const char **argv)
1052 {
1053         return net_ads_noads();
1054 }
1055
1056 int net_ads_help(int argc, const char **argv)
1057 {
1058         return net_ads_noads();
1059 }
1060
1061 int net_ads_join(int argc, const char **argv)
1062 {
1063         return net_ads_noads();
1064 }
1065
1066 int net_ads_user(int argc, const char **argv)
1067 {
1068         return net_ads_noads();
1069 }
1070
1071 int net_ads_group(int argc, const char **argv)
1072 {
1073         return net_ads_noads();
1074 }
1075
1076 /* this one shouldn't display a message */
1077 int net_ads_check(void)
1078 {
1079         return -1;
1080 }
1081
1082 int net_ads(int argc, const char **argv)
1083 {
1084         return net_ads_usage(argc, argv);
1085 }
1086
1087 #endif