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