r21606: Implement escaping function for ldap RDN values
[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    Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
22 */
23
24 #include "includes.h"
25 #include "utils/net.h"
26
27 #ifdef HAVE_ADS
28
29 int net_ads_usage(int argc, const char **argv)
30 {
31         d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
32         d_printf("    Join the local machine to a ADS realm\n");
33         d_printf("leave\n");
34         d_printf("    Remove the local machine from a ADS realm\n");
35         d_printf("testjoin\n");
36         d_printf("    Validates the machine account in the domain\n");
37         d_printf("user\n");
38         d_printf("    List, add, or delete users in the realm\n");
39         d_printf("group\n");
40         d_printf("    List, add, or delete groups in the realm\n");
41         d_printf("info\n");
42         d_printf("    Displays details regarding a specific AD server\n");
43         d_printf("status\n");
44         d_printf("    Display details regarding the machine's account in AD\n");
45         d_printf("lookup\n");
46         d_printf("    Performs CLDAP query of AD domain controllers\n");
47         d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
48         d_printf("    Change a user's password using an admin account\n");
49         d_printf("    (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
50         d_printf("changetrustpw\n");
51         d_printf("    Change the trust account password of this machine in the AD tree\n");
52         d_printf("printer [info | publish | remove] <printername> <servername>\n");
53         d_printf("    Lookup, add, or remove directory entry for a printer\n");
54         d_printf("{search,dn,sid}\n");
55         d_printf("    Issue LDAP search queries using a general filter, by DN, or by SID\n");
56         d_printf("keytab\n");
57         d_printf("    Manage a local keytab file based on the machine account in AD\n");
58         d_printf("dns\n");
59         d_printf("    Issue a dynamic DNS update request the server's hostname\n");
60         d_printf("    (using the machine credentials)\n");
61         
62         return -1;
63 }
64
65 /* when we do not have sufficient input parameters to contact a remote domain
66  * we always fall back to our own realm - Guenther*/
67
68 static const char *assume_own_realm(void)
69 {
70         if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
71                 return lp_realm();
72         }
73
74         return NULL;
75 }
76
77 /*
78   do a cldap netlogon query
79 */
80 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
81 {
82         struct cldap_netlogon_reply reply;
83
84         if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
85                 d_fprintf(stderr, "CLDAP query failed!\n");
86                 return -1;
87         }
88
89         d_printf("Information for Domain Controller: %s\n\n", 
90                 inet_ntoa(ads->ldap_ip));
91
92         d_printf("Response Type: ");
93         switch (reply.type) {
94         case SAMLOGON_AD_UNK_R:
95                 d_printf("SAMLOGON\n");
96                 break;
97         case SAMLOGON_AD_R:
98                 d_printf("SAMLOGON_USER\n");
99                 break;
100         default:
101                 d_printf("0x%x\n", reply.type);
102                 break;
103         }
104         d_printf("GUID: %s\n", 
105                  smb_uuid_string_static(smb_uuid_unpack_static(reply.guid))); 
106         d_printf("Flags:\n"
107                  "\tIs a PDC:                                   %s\n"
108                  "\tIs a GC of the forest:                      %s\n"
109                  "\tIs an LDAP server:                          %s\n"
110                  "\tSupports DS:                                %s\n"
111                  "\tIs running a KDC:                           %s\n"
112                  "\tIs running time services:                   %s\n"
113                  "\tIs the closest DC:                          %s\n"
114                  "\tIs writable:                                %s\n"
115                  "\tHas a hardware clock:                       %s\n"
116                  "\tIs a non-domain NC serviced by LDAP server: %s\n",
117                  (reply.flags & ADS_PDC) ? "yes" : "no",
118                  (reply.flags & ADS_GC) ? "yes" : "no",
119                  (reply.flags & ADS_LDAP) ? "yes" : "no",
120                  (reply.flags & ADS_DS) ? "yes" : "no",
121                  (reply.flags & ADS_KDC) ? "yes" : "no",
122                  (reply.flags & ADS_TIMESERV) ? "yes" : "no",
123                  (reply.flags & ADS_CLOSEST) ? "yes" : "no",
124                  (reply.flags & ADS_WRITABLE) ? "yes" : "no",
125                  (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
126                  (reply.flags & ADS_NDNC) ? "yes" : "no");
127
128         printf("Forest:\t\t\t%s\n", reply.forest);
129         printf("Domain:\t\t\t%s\n", reply.domain);
130         printf("Domain Controller:\t%s\n", reply.hostname);
131
132         printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
133         printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
134
135         if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
136         if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
137
138         printf("Server Site Name :\t\t%s\n", reply.server_site_name);
139         printf("Client Site Name :\t\t%s\n", reply.client_site_name);
140
141         d_printf("NT Version: %d\n", reply.version);
142         d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
143         d_printf("LM20 Token: %.2x\n", reply.lm20_token);
144
145         return 0;
146 }
147
148
149 /*
150   this implements the CLDAP based netlogon lookup requests
151   for finding the domain controller of a ADS domain
152 */
153 static int net_ads_lookup(int argc, const char **argv)
154 {
155         ADS_STRUCT *ads;
156
157         if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
158                 d_fprintf(stderr, "Didn't find the cldap server!\n");
159                 return -1;
160         }
161
162         if (!ads->config.realm) {
163                 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
164                 ads->ldap_port = 389;
165         }
166
167         return net_ads_cldap_netlogon(ads);
168 }
169
170
171
172 static int net_ads_info(int argc, const char **argv)
173 {
174         ADS_STRUCT *ads;
175
176         if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
177                 d_fprintf(stderr, "Didn't find the ldap server!\n");
178                 return -1;
179         }
180
181         if (!ads || !ads->config.realm) {
182                 d_fprintf(stderr, "Didn't find the ldap server!\n");
183                 return -1;
184         }
185
186         /* Try to set the server's current time since we didn't do a full
187            TCP LDAP session initially */
188
189         if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
190                 d_fprintf( stderr, "Failed to get server's current time!\n");
191         }
192
193         d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
194         d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
195         d_printf("Realm: %s\n", ads->config.realm);
196         d_printf("Bind Path: %s\n", ads->config.bind_path);
197         d_printf("LDAP port: %d\n", ads->ldap_port);
198         d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
199
200         d_printf("KDC server: %s\n", ads->auth.kdc_server );
201         d_printf("Server time offset: %d\n", ads->auth.time_offset );
202
203         return 0;
204 }
205
206 static void use_in_memory_ccache(void) {
207         /* Use in-memory credentials cache so we do not interfere with
208          * existing credentials */
209         setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
210 }
211
212 static ADS_STATUS ads_startup_int(BOOL only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
213 {
214         ADS_STRUCT *ads = NULL;
215         ADS_STATUS status;
216         BOOL need_password = False;
217         BOOL second_time = False;
218         char *cp;
219         const char *realm = NULL;
220         BOOL tried_closest_dc = False;
221
222         /* lp_realm() should be handled by a command line param, 
223            However, the join requires that realm be set in smb.conf
224            and compares our realm with the remote server's so this is
225            ok until someone needs more flexibility */
226
227         *ads_ret = NULL;
228
229 retry_connect:
230         if (only_own_domain) {
231                 realm = lp_realm();
232         } else {
233                 realm = assume_own_realm();
234         }
235
236         ads = ads_init(realm, opt_target_workgroup, opt_host);
237
238         if (!opt_user_name) {
239                 opt_user_name = "administrator";
240         }
241
242         if (opt_user_specified) {
243                 need_password = True;
244         }
245
246 retry:
247         if (!opt_password && need_password && !opt_machine_pass) {
248                 char *prompt = NULL;
249                 asprintf(&prompt,"%s's password: ", opt_user_name);
250                 if (!prompt) {
251                         ads_destroy(&ads);
252                         return ADS_ERROR(LDAP_NO_MEMORY);
253                 }
254                 opt_password = getpass(prompt);
255                 free(prompt);
256         }
257
258         if (opt_password) {
259                 use_in_memory_ccache();
260                 SAFE_FREE(ads->auth.password);
261                 ads->auth.password = smb_xstrdup(opt_password);
262         }
263
264         ads->auth.flags |= auth_flags;
265         SAFE_FREE(ads->auth.user_name);
266         ads->auth.user_name = smb_xstrdup(opt_user_name);
267
268        /*
269         * If the username is of the form "name@realm", 
270         * extract the realm and convert to upper case.
271         * This is only used to establish the connection.
272         */
273        if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
274                 *cp++ = '\0';
275                 SAFE_FREE(ads->auth.realm);
276                 ads->auth.realm = smb_xstrdup(cp);
277                 strupper_m(ads->auth.realm);
278        }
279
280         status = ads_connect(ads);
281
282         if (!ADS_ERR_OK(status)) {
283
284                 if (NT_STATUS_EQUAL(ads_ntstatus(status), 
285                                     NT_STATUS_NO_LOGON_SERVERS)) {
286                         DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
287                         ads_destroy(&ads);
288                         return status;
289                 }
290         
291                 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
292                         need_password = True;
293                         second_time = True;
294                         goto retry;
295                 } else {
296                         ads_destroy(&ads);
297                         return status;
298                 }
299         }
300
301         /* when contacting our own domain, make sure we use the closest DC.
302          * This is done by reconnecting to ADS because only the first call to
303          * ads_connect will give us our own sitename */
304
305         if ((only_own_domain || !opt_host) && !tried_closest_dc) {
306
307                 tried_closest_dc = True; /* avoid loop */
308
309                 if (!ads->config.tried_closest_dc) {
310
311                         namecache_delete(ads->server.realm, 0x1C);
312                         namecache_delete(ads->server.workgroup, 0x1C);
313
314                         ads_destroy(&ads);
315                         ads = NULL;
316
317                         goto retry_connect;
318                 }
319         }
320
321         *ads_ret = ads;
322         return status;
323 }
324
325 ADS_STATUS ads_startup(BOOL only_own_domain, ADS_STRUCT **ads)
326 {
327         return ads_startup_int(only_own_domain, 0, ads);
328 }
329
330 ADS_STATUS ads_startup_nobind(BOOL only_own_domain, ADS_STRUCT **ads)
331 {
332         return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
333 }
334
335 /*
336   Check to see if connection can be made via ads.
337   ads_startup() stores the password in opt_password if it needs to so
338   that rpc or rap can use it without re-prompting.
339 */
340 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
341 {
342         ADS_STRUCT *ads;
343         ADS_STATUS status;
344
345         if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
346                 return -1;
347         }
348
349         ads->auth.flags |= ADS_AUTH_NO_BIND;
350
351         status = ads_connect(ads);
352         if ( !ADS_ERR_OK(status) ) {
353                 return -1;
354         }
355
356         ads_destroy(&ads);
357         return 0;
358 }
359
360 int net_ads_check_our_domain(void)
361 {
362         return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
363 }
364
365 int net_ads_check(void)
366 {
367         return net_ads_check_int(NULL, opt_workgroup, opt_host);
368 }
369 /* 
370    determine the netbios workgroup name for a domain
371  */
372 static int net_ads_workgroup(int argc, const char **argv)
373 {
374         ADS_STRUCT *ads;
375         struct cldap_netlogon_reply reply;
376
377         if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
378                 d_fprintf(stderr, "Didn't find the cldap server!\n");
379                 return -1;
380         }
381         
382         if (!ads->config.realm) {
383                 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
384                 ads->ldap_port = 389;
385         }
386         
387         if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
388                 d_fprintf(stderr, "CLDAP query failed!\n");
389                 return -1;
390         }
391
392         d_printf("Workgroup: %s\n", reply.netbios_domain);
393
394         ads_destroy(&ads);
395         
396         return 0;
397 }
398
399
400
401 static BOOL usergrp_display(char *field, void **values, void *data_area)
402 {
403         char **disp_fields = (char **) data_area;
404
405         if (!field) { /* must be end of record */
406                 if (disp_fields[0]) {
407                         if (!strchr_m(disp_fields[0], '$')) {
408                                 if (disp_fields[1])
409                                         d_printf("%-21.21s %s\n", 
410                                                disp_fields[0], disp_fields[1]);
411                                 else
412                                         d_printf("%s\n", disp_fields[0]);
413                         }
414                 }
415                 SAFE_FREE(disp_fields[0]);
416                 SAFE_FREE(disp_fields[1]);
417                 return True;
418         }
419         if (!values) /* must be new field, indicate string field */
420                 return True;
421         if (StrCaseCmp(field, "sAMAccountName") == 0) {
422                 disp_fields[0] = SMB_STRDUP((char *) values[0]);
423         }
424         if (StrCaseCmp(field, "description") == 0)
425                 disp_fields[1] = SMB_STRDUP((char *) values[0]);
426         return True;
427 }
428
429 static int net_ads_user_usage(int argc, const char **argv)
430 {
431         return net_help_user(argc, argv);
432
433
434 static int ads_user_add(int argc, const char **argv)
435 {
436         ADS_STRUCT *ads;
437         ADS_STATUS status;
438         char *upn, *userdn;
439         LDAPMessage *res=NULL;
440         int rc = -1;
441         char *ou_str = NULL;
442
443         if (argc < 1) return net_ads_user_usage(argc, argv);
444         
445         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
446                 return -1;
447         }
448
449         status = ads_find_user_acct(ads, &res, argv[0]);
450
451         if (!ADS_ERR_OK(status)) {
452                 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
453                 goto done;
454         }
455         
456         if (ads_count_replies(ads, res)) {
457                 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
458                 goto done;
459         }
460
461         if (opt_container) {
462                 ou_str = SMB_STRDUP(opt_container);
463         } else {
464                 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
465         }
466
467         status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
468
469         if (!ADS_ERR_OK(status)) {
470                 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
471                          ads_errstr(status));
472                 goto done;
473         }
474
475         /* if no password is to be set, we're done */
476         if (argc == 1) { 
477                 d_printf("User %s added\n", argv[0]);
478                 rc = 0;
479                 goto done;
480         }
481
482         /* try setting the password */
483         asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
484         status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1], 
485                                        ads->auth.time_offset);
486         safe_free(upn);
487         if (ADS_ERR_OK(status)) {
488                 d_printf("User %s added\n", argv[0]);
489                 rc = 0;
490                 goto done;
491         }
492
493         /* password didn't set, delete account */
494         d_fprintf(stderr, "Could not add user %s.  Error setting password %s\n",
495                  argv[0], ads_errstr(status));
496         ads_msgfree(ads, res);
497         status=ads_find_user_acct(ads, &res, argv[0]);
498         if (ADS_ERR_OK(status)) {
499                 userdn = ads_get_dn(ads, res);
500                 ads_del_dn(ads, userdn);
501                 ads_memfree(ads, userdn);
502         }
503
504  done:
505         if (res)
506                 ads_msgfree(ads, res);
507         ads_destroy(&ads);
508         SAFE_FREE(ou_str);
509         return rc;
510 }
511
512 static int ads_user_info(int argc, const char **argv)
513 {
514         ADS_STRUCT *ads;
515         ADS_STATUS rc;
516         LDAPMessage *res;
517         const char *attrs[] = {"memberOf", NULL};
518         char *searchstring=NULL;
519         char **grouplist;
520         char *escaped_user;
521
522         if (argc < 1) {
523                 return net_ads_user_usage(argc, argv);
524         }
525
526         escaped_user = escape_ldap_string_alloc(argv[0]);
527
528         if (!escaped_user) {
529                 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
530                 return -1;
531         }
532
533         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
534                 SAFE_FREE(escaped_user);
535                 return -1;
536         }
537
538         asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
539         rc = ads_search(ads, &res, searchstring, attrs);
540         safe_free(searchstring);
541
542         if (!ADS_ERR_OK(rc)) {
543                 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
544                 ads_destroy(&ads);
545                 SAFE_FREE(escaped_user);
546                 return -1;
547         }
548         
549         grouplist = ldap_get_values((LDAP *)ads->ld,
550                                     (LDAPMessage *)res, "memberOf");
551
552         if (grouplist) {
553                 int i;
554                 char **groupname;
555                 for (i=0;grouplist[i];i++) {
556                         groupname = ldap_explode_dn(grouplist[i], 1);
557                         d_printf("%s\n", groupname[0]);
558                         ldap_value_free(groupname);
559                 }
560                 ldap_value_free(grouplist);
561         }
562         
563         ads_msgfree(ads, res);
564         ads_destroy(&ads);
565         SAFE_FREE(escaped_user);
566         return 0;
567 }
568
569 static int ads_user_delete(int argc, const char **argv)
570 {
571         ADS_STRUCT *ads;
572         ADS_STATUS rc;
573         LDAPMessage *res = NULL;
574         char *userdn;
575
576         if (argc < 1) {
577                 return net_ads_user_usage(argc, argv);
578         }
579         
580         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
581                 return -1;
582         }
583
584         rc = ads_find_user_acct(ads, &res, argv[0]);
585         if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
586                 d_printf("User %s does not exist.\n", argv[0]);
587                 ads_msgfree(ads, res);
588                 ads_destroy(&ads);
589                 return -1;
590         }
591         userdn = ads_get_dn(ads, res);
592         ads_msgfree(ads, res);
593         rc = ads_del_dn(ads, userdn);
594         ads_memfree(ads, userdn);
595         if (ADS_ERR_OK(rc)) {
596                 d_printf("User %s deleted\n", argv[0]);
597                 ads_destroy(&ads);
598                 return 0;
599         }
600         d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0], 
601                  ads_errstr(rc));
602         ads_destroy(&ads);
603         return -1;
604 }
605
606 int net_ads_user(int argc, const char **argv)
607 {
608         struct functable func[] = {
609                 {"ADD", ads_user_add},
610                 {"INFO", ads_user_info},
611                 {"DELETE", ads_user_delete},
612                 {NULL, NULL}
613         };
614         ADS_STRUCT *ads;
615         ADS_STATUS rc;
616         const char *shortattrs[] = {"sAMAccountName", NULL};
617         const char *longattrs[] = {"sAMAccountName", "description", NULL};
618         char *disp_fields[2] = {NULL, NULL};
619         
620         if (argc == 0) {
621                 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
622                         return -1;
623                 }
624
625                 if (opt_long_list_entries)
626                         d_printf("\nUser name             Comment"\
627                                  "\n-----------------------------\n");
628
629                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
630                                           LDAP_SCOPE_SUBTREE,
631                                           "(objectCategory=user)", 
632                                           opt_long_list_entries ? longattrs :
633                                           shortattrs, usergrp_display, 
634                                           disp_fields);
635                 ads_destroy(&ads);
636                 return ADS_ERR_OK(rc) ? 0 : -1;
637         }
638
639         return net_run_function(argc, argv, func, net_ads_user_usage);
640 }
641
642 static int net_ads_group_usage(int argc, const char **argv)
643 {
644         return net_help_group(argc, argv);
645
646
647 static int ads_group_add(int argc, const char **argv)
648 {
649         ADS_STRUCT *ads;
650         ADS_STATUS status;
651         LDAPMessage *res=NULL;
652         int rc = -1;
653         char *ou_str = NULL;
654
655         if (argc < 1) {
656                 return net_ads_group_usage(argc, argv);
657         }
658         
659         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
660                 return -1;
661         }
662
663         status = ads_find_user_acct(ads, &res, argv[0]);
664
665         if (!ADS_ERR_OK(status)) {
666                 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
667                 goto done;
668         }
669         
670         if (ads_count_replies(ads, res)) {
671                 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
672                 goto done;
673         }
674
675         if (opt_container) {
676                 ou_str = SMB_STRDUP(opt_container);
677         } else {
678                 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
679         }
680
681         status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
682
683         if (ADS_ERR_OK(status)) {
684                 d_printf("Group %s added\n", argv[0]);
685                 rc = 0;
686         } else {
687                 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
688                          ads_errstr(status));
689         }
690
691  done:
692         if (res)
693                 ads_msgfree(ads, res);
694         ads_destroy(&ads);
695         SAFE_FREE(ou_str);
696         return rc;
697 }
698
699 static int ads_group_delete(int argc, const char **argv)
700 {
701         ADS_STRUCT *ads;
702         ADS_STATUS rc;
703         LDAPMessage *res = NULL;
704         char *groupdn;
705
706         if (argc < 1) {
707                 return net_ads_group_usage(argc, argv);
708         }
709         
710         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
711                 return -1;
712         }
713
714         rc = ads_find_user_acct(ads, &res, argv[0]);
715         if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
716                 d_printf("Group %s does not exist.\n", argv[0]);
717                 ads_msgfree(ads, res);
718                 ads_destroy(&ads);
719                 return -1;
720         }
721         groupdn = ads_get_dn(ads, res);
722         ads_msgfree(ads, res);
723         rc = ads_del_dn(ads, groupdn);
724         ads_memfree(ads, groupdn);
725         if (ADS_ERR_OK(rc)) {
726                 d_printf("Group %s deleted\n", argv[0]);
727                 ads_destroy(&ads);
728                 return 0;
729         }
730         d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0], 
731                  ads_errstr(rc));
732         ads_destroy(&ads);
733         return -1;
734 }
735
736 int net_ads_group(int argc, const char **argv)
737 {
738         struct functable func[] = {
739                 {"ADD", ads_group_add},
740                 {"DELETE", ads_group_delete},
741                 {NULL, NULL}
742         };
743         ADS_STRUCT *ads;
744         ADS_STATUS rc;
745         const char *shortattrs[] = {"sAMAccountName", NULL};
746         const char *longattrs[] = {"sAMAccountName", "description", NULL};
747         char *disp_fields[2] = {NULL, NULL};
748
749         if (argc == 0) {
750                 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
751                         return -1;
752                 }
753
754                 if (opt_long_list_entries)
755                         d_printf("\nGroup name            Comment"\
756                                  "\n-----------------------------\n");
757                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
758                                           LDAP_SCOPE_SUBTREE, 
759                                           "(objectCategory=group)", 
760                                           opt_long_list_entries ? longattrs : 
761                                           shortattrs, usergrp_display, 
762                                           disp_fields);
763
764                 ads_destroy(&ads);
765                 return ADS_ERR_OK(rc) ? 0 : -1;
766         }
767         return net_run_function(argc, argv, func, net_ads_group_usage);
768 }
769
770 static int net_ads_status(int argc, const char **argv)
771 {
772         ADS_STRUCT *ads;
773         ADS_STATUS rc;
774         LDAPMessage *res;
775
776         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
777                 return -1;
778         }
779
780         rc = ads_find_machine_acct(ads, &res, global_myname());
781         if (!ADS_ERR_OK(rc)) {
782                 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
783                 ads_destroy(&ads);
784                 return -1;
785         }
786
787         if (ads_count_replies(ads, res) == 0) {
788                 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
789                 ads_destroy(&ads);
790                 return -1;
791         }
792
793         ads_dump(ads, res);
794         ads_destroy(&ads);
795         return 0;
796 }
797
798 /*******************************************************************
799  Leave an AD domain.  Windows XP disables the machine account.
800  We'll try the same.  The old code would do an LDAP delete.
801  That only worked using the machine creds because added the machine
802  with full control to the computer object's ACL.
803 *******************************************************************/
804
805 static int net_ads_leave(int argc, const char **argv)
806 {
807         ADS_STRUCT *ads = NULL;
808         ADS_STATUS adsret;
809         NTSTATUS status;
810         int ret = -1;
811         struct cli_state *cli = NULL;
812         TALLOC_CTX *ctx;
813         DOM_SID *dom_sid = NULL;
814         char *short_domain_name = NULL;      
815
816         if (!secrets_init()) {
817                 DEBUG(1,("Failed to initialise secrets database\n"));
818                 return -1;
819         }
820
821         if (!(ctx = talloc_init("net_ads_leave"))) {
822                 d_fprintf(stderr, "Could not initialise talloc context.\n");
823                 return -1;
824         }
825
826         /* The finds a DC and takes care of getting the 
827            user creds if necessary */
828
829         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
830                 return -1;
831         }
832
833         /* make RPC calls here */
834
835         if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap_ip, 
836                 ads->config.ldap_server_name)) )
837         {
838                 goto done;
839         }
840         
841         if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &short_domain_name, &dom_sid )) ) {
842                 goto done;
843         }
844
845         saf_delete( short_domain_name );
846
847         status = netdom_leave_domain(ctx, cli, dom_sid);
848
849         /* Try and delete it via LDAP - the old way we used to. */
850
851         adsret = ads_leave_realm(ads, global_myname());
852         if (ADS_ERR_OK(adsret)) {
853                 d_printf("Deleted account for '%s' in realm '%s'\n",
854                         global_myname(), ads->config.realm);
855                 ret = 0;
856         } else {
857                 /* We couldn't delete it - see if the disable succeeded. */
858                 if (NT_STATUS_IS_OK(status)) {
859                         d_printf("Disabled account for '%s' in realm '%s'\n",
860                                 global_myname(), ads->config.realm);
861                         ret = 0;
862                 } else {
863                         d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
864                                 global_myname(), ads->config.realm);
865                 }
866         }
867
868 done:
869
870         if ( cli ) 
871                 cli_shutdown(cli);
872
873         ads_destroy(&ads);
874         TALLOC_FREE( ctx );
875
876         return ret;
877 }
878
879 static NTSTATUS net_ads_join_ok(void)
880 {
881         ADS_STRUCT *ads = NULL;
882         ADS_STATUS status;
883
884         if (!secrets_init()) {
885                 DEBUG(1,("Failed to initialise secrets database\n"));
886                 return NT_STATUS_ACCESS_DENIED;
887         }
888
889         net_use_machine_password();
890
891         status = ads_startup(True, &ads);
892         if (!ADS_ERR_OK(status)) {
893                 return ads_ntstatus(status);
894         }
895
896         ads_destroy(&ads);
897         return NT_STATUS_OK;
898 }
899
900 /*
901   check that an existing join is OK
902  */
903 int net_ads_testjoin(int argc, const char **argv)
904 {
905         NTSTATUS status;
906         use_in_memory_ccache();
907
908         /* Display success or failure */
909         status = net_ads_join_ok();
910         if (!NT_STATUS_IS_OK(status)) {
911                 fprintf(stderr,"Join to domain is not valid: %s\n", 
912                         get_friendly_nt_error_msg(status));
913                 return -1;
914         }
915
916         printf("Join is OK\n");
917         return 0;
918 }
919
920 /*******************************************************************
921   Simple configu checks before beginning the join
922  ********************************************************************/
923
924 static NTSTATUS check_ads_config( void )
925 {
926         if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
927                 d_printf("Host is not configured as a member server.\n");
928                 return NT_STATUS_INVALID_DOMAIN_ROLE;
929         }
930
931         if (strlen(global_myname()) > 15) {
932                 d_printf("Our netbios name can be at most 15 chars long, "
933                          "\"%s\" is %u chars long\n", global_myname(),
934                          (unsigned int)strlen(global_myname()));
935                 return NT_STATUS_NAME_TOO_LONG;
936         }
937
938         if ( lp_security() == SEC_ADS && !*lp_realm()) {
939                 d_fprintf(stderr, "realm must be set in in %s for ADS "
940                         "join to succeed.\n", dyn_CONFIGFILE);
941                 return NT_STATUS_INVALID_PARAMETER;
942         }
943
944         if (!secrets_init()) {
945                 DEBUG(1,("Failed to initialise secrets database\n"));
946                 /* This is a good bet for failure of secrets_init ... */
947                 return NT_STATUS_ACCESS_DENIED;
948         }
949         
950         return NT_STATUS_OK;
951 }
952
953 /*******************************************************************
954  Do the domain join
955  ********************************************************************/
956
957 static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername, 
958                                 struct in_addr *ip, char **domain, 
959                                 DOM_SID **dom_sid, 
960                                 const char *password)
961 {
962         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
963         struct cli_state *cli = NULL;
964
965         ret = connect_to_ipc_krb5(&cli, ip, servername);
966         if ( !NT_STATUS_IS_OK(ret) ) {
967                 goto done;
968         }
969         
970         ret = netdom_get_domain_sid( ctx, cli, domain, dom_sid );
971         if ( !NT_STATUS_IS_OK(ret) ) {
972                 goto done;
973         }
974
975         /* cli->server_domain is not filled in when using krb5 
976            session setups */
977
978         saf_store( *domain, cli->desthost );
979
980         ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
981
982 done:
983         if ( cli ) 
984                 cli_shutdown(cli);
985
986         return ret;
987 }
988
989 /*******************************************************************
990  Set a machines dNSHostName and servicePrincipalName attributes
991  ********************************************************************/
992
993 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
994 {
995         ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
996         char *new_dn;
997         ADS_MODLIST mods;
998         const char *servicePrincipalName[3] = {NULL, NULL, NULL};
999         char *psp;
1000         fstring my_fqdn;
1001         LDAPMessage *res = NULL;
1002         char *dn_string = NULL;
1003         const char *machine_name = global_myname();
1004         int count;
1005         
1006         if ( !machine_name ) {
1007                 return ADS_ERROR(LDAP_NO_MEMORY);
1008         }
1009         
1010         /* Find our DN */
1011         
1012         status = ads_find_machine_acct(ads_s, &res, machine_name);
1013         if (!ADS_ERR_OK(status)) 
1014                 return status;
1015                 
1016         if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1017                 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1018                 return ADS_ERROR(LDAP_NO_MEMORY);       
1019         }
1020         
1021         if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1022                 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1023                 goto done;
1024         }
1025         
1026         new_dn = talloc_strdup(ctx, dn_string);
1027         ads_memfree(ads_s, dn_string);
1028         if (!new_dn) {
1029                 return ADS_ERROR(LDAP_NO_MEMORY);
1030         }
1031
1032         /* Windows only creates HOST/shortname & HOST/fqdn. */
1033            
1034         if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) ) 
1035                 goto done;
1036         strupper_m(psp);
1037         servicePrincipalName[0] = psp;
1038
1039         name_to_fqdn(my_fqdn, machine_name);
1040         strlower_m(my_fqdn);
1041         if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) ) 
1042                 goto done;
1043         servicePrincipalName[1] = psp;
1044         
1045         if (!(mods = ads_init_mods(ctx))) {
1046                 goto done;
1047         }
1048         
1049         /* fields of primary importance */
1050         
1051         ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
1052         ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1053
1054         status = ads_gen_mod(ads_s, new_dn, mods);
1055
1056 done:
1057         ads_msgfree(ads_s, res);
1058         
1059         return status;
1060 }
1061
1062 /*******************************************************************
1063  Set a machines dNSHostName and servicePrincipalName attributes
1064  ********************************************************************/
1065
1066 static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
1067 {
1068         ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1069         char *new_dn;
1070         ADS_MODLIST mods;
1071         LDAPMessage *res = NULL;
1072         char *dn_string = NULL;
1073         const char *machine_name = global_myname();
1074         int count;
1075         
1076         if ( !machine_name ) {
1077                 return ADS_ERROR(LDAP_NO_MEMORY);
1078         }
1079         
1080         /* Find our DN */
1081         
1082         status = ads_find_machine_acct(ads_s, &res, machine_name);
1083         if (!ADS_ERR_OK(status)) 
1084                 return status;
1085                 
1086         if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1087                 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1088                 return ADS_ERROR(LDAP_NO_MEMORY);       
1089         }
1090         
1091         if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1092                 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1093                 goto done;
1094         }
1095         
1096         new_dn = talloc_strdup(ctx, dn_string);
1097         ads_memfree(ads_s, dn_string);
1098         if (!new_dn) {
1099                 return ADS_ERROR(LDAP_NO_MEMORY);
1100         }
1101         
1102         /* now do the mods */
1103         
1104         if (!(mods = ads_init_mods(ctx))) {
1105                 goto done;
1106         }
1107         
1108         /* fields of primary importance */
1109         
1110         ads_mod_str(ctx, &mods, "userPrincipalName", upn);
1111
1112         status = ads_gen_mod(ads_s, new_dn, mods);
1113
1114 done:
1115         ads_msgfree(ads_s, res);
1116         
1117         return status;
1118 }
1119
1120 /*******************************************************************
1121   join a domain using ADS (LDAP mods)
1122  ********************************************************************/
1123
1124 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
1125 {
1126         ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
1127         char *dn, *ou_str;
1128         LDAPMessage *res = NULL;
1129
1130         ou_str = ads_ou_string(ads, ou);
1131         if ((asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path)) == -1) {
1132                 SAFE_FREE(ou_str);
1133                 return ADS_ERROR(LDAP_NO_MEMORY);
1134         }
1135
1136         rc = ads_search_dn(ads, &res, dn, NULL);
1137         ads_msgfree(ads, res);
1138
1139         if (ADS_ERR_OK(rc)) {
1140                 /* Attempt to create the machine account and bail if this fails.
1141                    Assume that the admin wants exactly what they requested */
1142
1143                 rc = ads_create_machine_acct( ads, global_myname(), dn );
1144                 if ( rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS ) {
1145                         rc = ADS_SUCCESS;
1146                 }
1147         }
1148
1149         SAFE_FREE( ou_str );
1150         SAFE_FREE( dn );
1151
1152         return rc;
1153 }
1154
1155 /************************************************************************
1156  ************************************************************************/
1157
1158 static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1159 {
1160         uint32 domain_func;
1161         ADS_STATUS status;
1162         fstring salt;
1163         char *std_salt;
1164         LDAPMessage *res = NULL;
1165         const char *machine_name = global_myname();
1166
1167         status = ads_domain_func_level( ads, &domain_func );
1168         if ( !ADS_ERR_OK(status) ) {
1169                 DEBUG(2,("Failed to determine domain functional level!\n"));
1170                 return False;
1171         }
1172
1173         /* go ahead and setup the default salt */
1174
1175         if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
1176                 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
1177                 return False;
1178         }
1179
1180         fstrcpy( salt, std_salt );
1181         SAFE_FREE( std_salt );
1182         
1183         /* if it's a Windows functional domain, we have to look for the UPN */
1184            
1185         if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) { 
1186                 char *upn;
1187                 int count;
1188                 
1189                 status = ads_find_machine_acct(ads, &res, machine_name);
1190                 if (!ADS_ERR_OK(status)) {
1191                         return False;
1192                 }
1193                 
1194                 if ( (count = ads_count_replies(ads, res)) != 1 ) {
1195                         DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1196                         return False;
1197                 }
1198                 
1199                 upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
1200                 if ( upn ) {
1201                         fstrcpy( salt, upn );
1202                 }
1203                 
1204                 ads_msgfree(ads, res);
1205         }
1206
1207         return kerberos_secrets_store_des_salt( salt );
1208 }
1209
1210 /*******************************************************************
1211  Send a DNS update request
1212 *******************************************************************/
1213
1214 #if defined(WITH_DNS_UPDATES)
1215 #include "dns.h"
1216 DNS_ERROR DoDNSUpdate(char *pszServerName,
1217                       const char *pszDomainName,
1218                       const char *pszHostName,
1219                       const struct in_addr *iplist, int num_addrs );
1220
1221
1222 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1223                                         const char *machine_name,
1224                                         const struct in_addr *addrs,
1225                                         int num_addrs)
1226 {
1227         struct dns_rr_ns *nameservers = NULL;
1228         int ns_count = 0;
1229         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1230         DNS_ERROR dns_err;
1231         fstring dns_server;
1232         const char *dnsdomain = NULL;   
1233         char *root_domain = NULL;       
1234
1235         if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1236                 d_printf("No DNS domain configured for %s. "
1237                          "Unable to perform DNS Update.\n", machine_name);
1238                 status = NT_STATUS_INVALID_PARAMETER;
1239                 goto done;
1240         }
1241         dnsdomain++;
1242
1243         status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1244         if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1245                 /* Child domains often do not have NS records.  Look
1246                    for the NS record for the forest root domain 
1247                    (rootDomainNamingContext in therootDSE) */
1248
1249                 const char *rootname_attrs[] =  { "rootDomainNamingContext", NULL };
1250                 LDAPMessage *msg = NULL;
1251                 char *root_dn;
1252                 ADS_STATUS ads_status;
1253                 
1254                 if ( !ads->ld ) {
1255                         ads_status = ads_connect( ads );
1256                         if ( !ADS_ERR_OK(ads_status) ) {
1257                                 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1258                                 goto done;                              
1259                         }                       
1260                 }
1261                 
1262                 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE, 
1263                                        "(objectclass=*)", rootname_attrs, &msg);
1264                 if (!ADS_ERR_OK(ads_status)) {
1265                         goto done;
1266                 }
1267
1268                 root_dn = ads_pull_string(ads, ctx, msg,  "rootDomainNamingContext");
1269                 if ( !root_dn ) {
1270                         ads_msgfree( ads, msg );                        
1271                         goto done;
1272                 }
1273
1274                 root_domain = ads_build_domain( root_dn );
1275
1276                 /* cleanup */
1277                 ads_msgfree( ads, msg );
1278
1279                 /* try again for NS servers */
1280
1281                 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1282                 
1283                 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {                     
1284                         DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1285                          "realm\n", ads->config.realm));
1286                         goto done;
1287                 }
1288
1289                 dnsdomain = root_domain;                
1290                 
1291         }
1292
1293         /* Now perform the dns update - we'll try non-secure and if we fail,
1294            we'll follow it up with a secure update */
1295
1296         fstrcpy( dns_server, nameservers[0].hostname );
1297
1298         dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1299         if (!ERR_DNS_IS_OK(dns_err)) {
1300                 status = NT_STATUS_UNSUCCESSFUL;
1301         }
1302
1303 done:
1304
1305         SAFE_FREE( root_domain );
1306         
1307         return status;
1308 }
1309
1310 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1311 {
1312         int num_addrs;
1313         struct in_addr *iplist = NULL;
1314         fstring machine_name;
1315         NTSTATUS status;
1316
1317         name_to_fqdn( machine_name, global_myname() );
1318         strlower_m( machine_name );
1319
1320         /* Get our ip address (not the 127.0.0.x address but a real ip
1321          * address) */
1322
1323         num_addrs = get_my_ip_address( &iplist );
1324         if ( num_addrs <= 0 ) {
1325                 DEBUG(4,("net_ads_join: Failed to find my non-loopback IP "
1326                          "addresses!\n"));
1327                 return NT_STATUS_INVALID_PARAMETER;
1328         }
1329
1330         status = net_update_dns_internal(mem_ctx, ads, machine_name,
1331                                          iplist, num_addrs);
1332         SAFE_FREE( iplist );
1333         return status;
1334 }
1335 #endif
1336
1337
1338 /*******************************************************************
1339  utility function to parse an integer parameter from 
1340  "parameter = value"
1341 **********************************************************/
1342 static char* get_string_param( const char* param )
1343 {
1344         char *p;
1345         
1346         if ( (p = strchr( param, '=' )) == NULL )
1347                 return NULL;
1348                 
1349         return (p+1);
1350 }
1351
1352 /*******************************************************************
1353  ********************************************************************/
1354  
1355 static int net_ads_join_usage(int argc, const char **argv)
1356 {
1357         d_printf("net ads join [options]\n");
1358         d_printf("Valid options:\n");
1359         d_printf("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n");
1360         d_printf("                      The deault UPN is in the form host/netbiosname@REALM.\n");
1361         d_printf("   createcomputer=OU  Precreate the computer account in a specific OU.\n");
1362         d_printf("                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1363         d_printf("                      E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1364         d_printf("                      NB: A backslash '\\' is used as escape at multiple levels and may\n");
1365         d_printf("                          need to be doubled or even quadrupled.  It is not used as a separator");
1366
1367         return -1;
1368 }
1369
1370 /*******************************************************************
1371  ********************************************************************/
1372  
1373 int net_ads_join(int argc, const char **argv)
1374 {
1375         ADS_STRUCT *ads = NULL;
1376         ADS_STATUS status;
1377         NTSTATUS nt_status;
1378         char *machine_account = NULL;
1379         char *short_domain_name = NULL;
1380         char *tmp_password, *password;
1381         TALLOC_CTX *ctx = NULL;
1382         DOM_SID *domain_sid = NULL;
1383         BOOL createupn = False;
1384         const char *machineupn = NULL;
1385         const char *create_in_ou = NULL;
1386         int i;
1387         fstring dc_name;
1388         struct in_addr dcip;
1389         
1390         nt_status = check_ads_config();
1391         if (!NT_STATUS_IS_OK(nt_status)) {
1392                 d_fprintf(stderr, "Invalid configuration.  Exiting....\n");
1393                 goto fail;
1394         }
1395
1396         /* find a DC to initialize the server affinity cache */
1397
1398         get_dc_name( lp_workgroup(), lp_realm(), dc_name, &dcip );
1399
1400         status = ads_startup(True, &ads);
1401         if (!ADS_ERR_OK(status)) {
1402                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1403                 nt_status = ads_ntstatus(status);
1404                 goto fail;
1405         }
1406
1407         if (strcmp(ads->config.realm, lp_realm()) != 0) {
1408                 d_fprintf(stderr, "realm of remote server (%s) and realm in %s "
1409                         "(%s) DO NOT match.  Aborting join\n", ads->config.realm, 
1410                         dyn_CONFIGFILE, lp_realm());
1411                 nt_status = NT_STATUS_INVALID_PARAMETER;
1412                 goto fail;
1413         }
1414
1415         if (!(ctx = talloc_init("net_ads_join"))) {
1416                 d_fprintf(stderr, "Could not initialise talloc context.\n");
1417                 nt_status = NT_STATUS_NO_MEMORY;
1418                 goto fail;
1419         }
1420
1421         /* process additional command line args */
1422         
1423         for ( i=0; i<argc; i++ ) {
1424                 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1425                         createupn = True;
1426                         machineupn = get_string_param(argv[i]);
1427                 }
1428                 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1429                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1430                                 d_fprintf(stderr, "Please supply a valid OU path\n");
1431                                 nt_status = NT_STATUS_INVALID_PARAMETER;
1432                                 goto fail;
1433                         }               
1434                 }
1435                 else {
1436                         d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1437                         nt_status = NT_STATUS_INVALID_PARAMETER;
1438                         goto fail;
1439                 }
1440         }
1441
1442         /* If we were given an OU, try to create the machine in 
1443            the OU account first and then do the normal RPC join */
1444
1445         if  ( create_in_ou ) {
1446                 status = net_precreate_machine_acct( ads, create_in_ou );
1447                 if ( !ADS_ERR_OK(status) ) {
1448                         d_fprintf( stderr, "Failed to pre-create the machine object "
1449                                 "in OU %s.\n", argv[0]);
1450                         DEBUG(1, ("error calling net_precreate_machine_acct: %s\n", 
1451                                   ads_errstr(status)));
1452                         nt_status = ads_ntstatus(status);
1453                         goto fail;
1454                 }
1455         }
1456
1457         /* Do the domain join here */
1458
1459         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1460         password = talloc_strdup(ctx, tmp_password);
1461         
1462         nt_status = net_join_domain(ctx, ads->config.ldap_server_name, 
1463                                     &ads->ldap_ip, &short_domain_name, &domain_sid, password);
1464         if ( !NT_STATUS_IS_OK(nt_status) ) {
1465                 DEBUG(1, ("call of net_join_domain failed: %s\n", 
1466                           get_friendly_nt_error_msg(nt_status)));
1467                 goto fail;
1468         }
1469
1470         /* Check the short name of the domain */
1471         
1472         if ( !strequal(lp_workgroup(), short_domain_name) ) {
1473                 d_printf("The workgroup in %s does not match the short\n", dyn_CONFIGFILE);
1474                 d_printf("domain name obtained from the server.\n");
1475                 d_printf("Using the name [%s] from the server.\n", short_domain_name);
1476                 d_printf("You should set \"workgroup = %s\" in %s.\n", 
1477                          short_domain_name, dyn_CONFIGFILE);
1478         }
1479         
1480         d_printf("Using short domain name -- %s\n", short_domain_name);
1481
1482         /*  HACK ALERT!  Store the sid and password under both the lp_workgroup() 
1483             value from smb.conf and the string returned from the server.  The former is
1484             neede to bootstrap winbindd's first connection to the DC to get the real 
1485             short domain name   --jerry */
1486            
1487         if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
1488                 || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
1489         {
1490                 /* issue an internal error here for now.
1491                  * everything else would mean changing tdb routines. */
1492                 nt_status = NT_STATUS_INTERNAL_ERROR;
1493                 goto fail;
1494         }
1495
1496         /* Verify that everything is ok */
1497
1498         if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap_ip) != 0 ) {
1499                 d_fprintf(stderr, "Failed to verify membership in domain!\n");
1500                 goto fail;
1501         }       
1502
1503         /* create the dNSHostName & servicePrincipalName values */
1504         
1505         status = net_set_machine_spn( ctx, ads );
1506         if ( !ADS_ERR_OK(status) )  {
1507
1508                 d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
1509                 d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
1510                 d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
1511                 
1512                 /* Disable the machine account in AD.  Better to fail than to leave 
1513                    a confused admin.  */
1514                 
1515                 if ( net_ads_leave( 0, NULL ) != 0 ) {
1516                         d_fprintf( stderr, "Failed to disable machine account in AD.  Please do so manually.\n");
1517                 }
1518                 
1519                 /* clear out the machine password */
1520                 
1521                 netdom_store_machine_account( lp_workgroup(), domain_sid, "" ); 
1522                 netdom_store_machine_account( short_domain_name, domain_sid, "" );
1523                 
1524                 nt_status = ads_ntstatus(status);
1525                 goto fail;
1526         }
1527
1528         if ( !net_derive_salting_principal( ctx, ads ) ) {
1529                 DEBUG(1,("Failed to determine salting principal\n"));
1530                 goto fail;
1531         }
1532
1533         if ( createupn ) {
1534                 pstring upn;
1535                 
1536                 /* default to using the short UPN name */
1537                 if ( !machineupn ) {
1538                         snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(), 
1539                                 ads->config.realm );
1540                         machineupn = upn;
1541                 }
1542                 
1543                 status = net_set_machine_upn( ctx, ads, machineupn );
1544                 if ( !ADS_ERR_OK(status) )  {
1545                         d_fprintf(stderr, "Failed to set userPrincipalName.  Are you a Domain Admin?\n");
1546                 }
1547         }
1548
1549         /* Now build the keytab, using the same ADS connection */
1550         if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
1551                 DEBUG(1,("Error creating host keytab!\n"));
1552         }
1553
1554 #if defined(WITH_DNS_UPDATES)
1555         /* We enter this block with user creds */
1556         ads_kdestroy( NULL );   
1557         ads_destroy(&ads);
1558         ads = NULL;
1559         
1560         if ( (ads = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1561                 /* kinit with the machine password */
1562
1563                 use_in_memory_ccache();
1564                 asprintf( &ads->auth.user_name, "%s$", global_myname() );
1565                 ads->auth.password = secrets_fetch_machine_password(
1566                         lp_workgroup(), NULL, NULL );
1567                 ads->auth.realm = SMB_STRDUP( lp_realm() );
1568                 ads_kinit_password( ads );
1569         }
1570         
1571         if ( !ads || !NT_STATUS_IS_OK(net_update_dns( ctx, ads )) ) {
1572                 d_fprintf( stderr, "DNS update failed!\n" );
1573         }
1574         
1575         /* exit from this block using machine creds */
1576 #endif
1577
1578         d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->server.realm);
1579
1580         SAFE_FREE(machine_account);
1581         TALLOC_FREE( ctx );
1582         ads_destroy(&ads);
1583         
1584         return 0;
1585
1586 fail:
1587         /* issue an overall failure message at the end. */
1588         d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
1589
1590         SAFE_FREE(machine_account);
1591         TALLOC_FREE( ctx );
1592         ads_destroy(&ads);
1593
1594         return -1;
1595
1596 }
1597
1598 /*******************************************************************
1599  ********************************************************************/
1600  
1601 static int net_ads_dns_usage(int argc, const char **argv)
1602 {
1603 #if defined(WITH_DNS_UPDATES)
1604         d_printf("net ads dns <command>\n");
1605         d_printf("Valid commands:\n");
1606         d_printf("   register         Issue a dynamic DNS update request for our hostname\n");
1607
1608         return 0;
1609 #else
1610         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1611         return -1;
1612 #endif
1613 }
1614
1615 /*******************************************************************
1616  ********************************************************************/
1617  
1618 static int net_ads_dns_register(int argc, const char **argv)
1619 {
1620 #if defined(WITH_DNS_UPDATES)
1621         ADS_STRUCT *ads;
1622         ADS_STATUS status;
1623         TALLOC_CTX *ctx;
1624         
1625 #ifdef DEVELOPER
1626         talloc_enable_leak_report();
1627 #endif
1628         
1629         if (argc > 0) {
1630                 d_fprintf(stderr, "net ads dns register <name> <ip>\n");
1631                 return -1;
1632         }
1633
1634         if (!(ctx = talloc_init("net_ads_dns"))) {
1635                 d_fprintf(stderr, "Could not initialise talloc context\n");
1636                 return -1;
1637         }
1638
1639         status = ads_startup(True, &ads);
1640         if ( !ADS_ERR_OK(status) ) {
1641                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1642                 TALLOC_FREE(ctx);
1643                 return -1;
1644         }
1645
1646         if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {             
1647                 d_fprintf( stderr, "DNS update failed!\n" );
1648                 ads_destroy( &ads );
1649                 TALLOC_FREE( ctx );
1650                 return -1;
1651         }
1652         
1653         d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1654
1655         ads_destroy(&ads);
1656         TALLOC_FREE( ctx );
1657         
1658         return 0;
1659 #else
1660         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1661         return -1;
1662 #endif
1663 }
1664
1665 #if defined(WITH_DNS_UPDATES)
1666 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1667 #endif
1668
1669 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1670 {
1671 #if defined(WITH_DNS_UPDATES)
1672         DNS_ERROR err;
1673         
1674 #ifdef DEVELOPER
1675         talloc_enable_leak_report();
1676 #endif
1677
1678         if (argc != 2) {
1679                 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1680                           "<name>\n");
1681                 return -1;
1682         }
1683
1684         err = do_gethostbyname(argv[0], argv[1]);
1685
1686         d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1687 #endif
1688         return 0;
1689 }
1690
1691 static int net_ads_dns(int argc, const char *argv[])
1692 {
1693         struct functable func[] = {
1694                 {"REGISTER", net_ads_dns_register},
1695                 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1696                 {NULL, NULL}
1697         };
1698
1699         return net_run_function(argc, argv, func, net_ads_dns_usage);
1700 }
1701
1702 /*******************************************************************
1703  ********************************************************************/
1704
1705 int net_ads_printer_usage(int argc, const char **argv)
1706 {
1707         d_printf(
1708 "\nnet ads printer search <printer>"
1709 "\n\tsearch for a printer in the directory\n"
1710 "\nnet ads printer info <printer> <server>"
1711 "\n\tlookup info in directory for printer on server"
1712 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1713 "\nnet ads printer publish <printername>"
1714 "\n\tpublish printer in directory"
1715 "\n\t(note: printer name is required)\n"
1716 "\nnet ads printer remove <printername>"
1717 "\n\tremove printer from directory"
1718 "\n\t(note: printer name is required)\n");
1719         return -1;
1720 }
1721
1722 /*******************************************************************
1723  ********************************************************************/
1724
1725 static int net_ads_printer_search(int argc, const char **argv)
1726 {
1727         ADS_STRUCT *ads;
1728         ADS_STATUS rc;
1729         LDAPMessage *res = NULL;
1730
1731         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1732                 return -1;
1733         }
1734
1735         rc = ads_find_printers(ads, &res);
1736
1737         if (!ADS_ERR_OK(rc)) {
1738                 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1739                 ads_msgfree(ads, res);
1740                 ads_destroy(&ads);
1741                 return -1;
1742         }
1743
1744         if (ads_count_replies(ads, res) == 0) {
1745                 d_fprintf(stderr, "No results found\n");
1746                 ads_msgfree(ads, res);
1747                 ads_destroy(&ads);
1748                 return -1;
1749         }
1750
1751         ads_dump(ads, res);
1752         ads_msgfree(ads, res);
1753         ads_destroy(&ads);
1754         return 0;
1755 }
1756
1757 static int net_ads_printer_info(int argc, const char **argv)
1758 {
1759         ADS_STRUCT *ads;
1760         ADS_STATUS rc;
1761         const char *servername, *printername;
1762         LDAPMessage *res = NULL;
1763
1764         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1765                 return -1;
1766         }
1767
1768         if (argc > 0) {
1769                 printername = argv[0];
1770         } else {
1771                 printername = "*";
1772         }
1773
1774         if (argc > 1) {
1775                 servername =  argv[1];
1776         } else {
1777                 servername = global_myname();
1778         }
1779
1780         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1781
1782         if (!ADS_ERR_OK(rc)) {
1783                 d_fprintf(stderr, "Server '%s' not found: %s\n", 
1784                         servername, ads_errstr(rc));
1785                 ads_msgfree(ads, res);
1786                 ads_destroy(&ads);
1787                 return -1;
1788         }
1789
1790         if (ads_count_replies(ads, res) == 0) {
1791                 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1792                 ads_msgfree(ads, res);
1793                 ads_destroy(&ads);
1794                 return -1;
1795         }
1796
1797         ads_dump(ads, res);
1798         ads_msgfree(ads, res);
1799         ads_destroy(&ads);
1800
1801         return 0;
1802 }
1803
1804 void do_drv_upgrade_printer(int msg_type, struct process_id src,
1805                             void *buf, size_t len, void *private_data)
1806 {
1807         return;
1808 }
1809
1810 static int net_ads_printer_publish(int argc, const char **argv)
1811 {
1812         ADS_STRUCT *ads;
1813         ADS_STATUS rc;
1814         const char *servername, *printername;
1815         struct cli_state *cli;
1816         struct rpc_pipe_client *pipe_hnd;
1817         struct in_addr          server_ip;
1818         NTSTATUS nt_status;
1819         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1820         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1821         char *prt_dn, *srv_dn, **srv_cn;
1822         char *srv_cn_escaped, *printername_escaped;
1823         LDAPMessage *res = NULL;
1824
1825         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1826                 return -1;
1827         }
1828
1829         if (argc < 1) {
1830                 return net_ads_printer_usage(argc, argv);
1831         }
1832         
1833         printername = argv[0];
1834
1835         if (argc == 2) {
1836                 servername = argv[1];
1837         } else {
1838                 servername = global_myname();
1839         }
1840                 
1841         /* Get printer data from SPOOLSS */
1842
1843         resolve_name(servername, &server_ip, 0x20);
1844
1845         nt_status = cli_full_connection(&cli, global_myname(), servername, 
1846                                         &server_ip, 0,
1847                                         "IPC$", "IPC",  
1848                                         opt_user_name, opt_workgroup,
1849                                         opt_password ? opt_password : "", 
1850                                         CLI_FULL_CONNECTION_USE_KERBEROS, 
1851                                         Undefined, NULL);
1852
1853         if (NT_STATUS_IS_ERR(nt_status)) {
1854                 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1855                          "for %s\n", servername, printername);
1856                 ads_destroy(&ads);
1857                 return -1;
1858         }
1859
1860         /* Publish on AD server */
1861
1862         ads_find_machine_acct(ads, &res, servername);
1863
1864         if (ads_count_replies(ads, res) == 0) {
1865                 d_fprintf(stderr, "Could not find machine account for server %s\n", 
1866                          servername);
1867                 ads_destroy(&ads);
1868                 return -1;
1869         }
1870
1871         srv_dn = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res);
1872         srv_cn = ldap_explode_dn(srv_dn, 1);
1873
1874         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1875         printername_escaped = escape_rdn_val_string_alloc(printername);
1876         if (!srv_cn_escaped || !printername_escaped) {
1877                 d_fprintf(stderr, "Internal error, out of memory!");
1878                 ads_destroy(&ads);
1879                 return -1;
1880         }
1881
1882         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1883
1884         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1885         if (!pipe_hnd) {
1886                 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1887                          servername);
1888                 ads_destroy(&ads);
1889                 return -1;
1890         }
1891
1892         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1893                                                               printername))) {
1894                 ads_destroy(&ads);
1895                 return -1;
1896         }
1897
1898         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1899         if (!ADS_ERR_OK(rc)) {
1900                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1901                 ads_destroy(&ads);
1902                 return -1;
1903         }
1904  
1905         d_printf("published printer\n");
1906         ads_destroy(&ads);
1907  
1908         return 0;
1909 }
1910
1911 static int net_ads_printer_remove(int argc, const char **argv)
1912 {
1913         ADS_STRUCT *ads;
1914         ADS_STATUS rc;
1915         const char *servername;
1916         char *prt_dn;
1917         LDAPMessage *res = NULL;
1918
1919         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1920                 return -1;
1921         }
1922
1923         if (argc < 1) {
1924                 return net_ads_printer_usage(argc, argv);
1925         }
1926
1927         if (argc > 1) {
1928                 servername = argv[1];
1929         } else {
1930                 servername = global_myname();
1931         }
1932
1933         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1934
1935         if (!ADS_ERR_OK(rc)) {
1936                 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1937                 ads_msgfree(ads, res);
1938                 ads_destroy(&ads);
1939                 return -1;
1940         }
1941
1942         if (ads_count_replies(ads, res) == 0) {
1943                 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1944                 ads_msgfree(ads, res);
1945                 ads_destroy(&ads);
1946                 return -1;
1947         }
1948
1949         prt_dn = ads_get_dn(ads, res);
1950         ads_msgfree(ads, res);
1951         rc = ads_del_dn(ads, prt_dn);
1952         ads_memfree(ads, prt_dn);
1953
1954         if (!ADS_ERR_OK(rc)) {
1955                 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1956                 ads_destroy(&ads);
1957                 return -1;
1958         }
1959
1960         ads_destroy(&ads);
1961         return 0;
1962 }
1963
1964 static int net_ads_printer(int argc, const char **argv)
1965 {
1966         struct functable func[] = {
1967                 {"SEARCH", net_ads_printer_search},
1968                 {"INFO", net_ads_printer_info},
1969                 {"PUBLISH", net_ads_printer_publish},
1970                 {"REMOVE", net_ads_printer_remove},
1971                 {NULL, NULL}
1972         };
1973         
1974         return net_run_function(argc, argv, func, net_ads_printer_usage);
1975 }
1976
1977
1978 static int net_ads_password(int argc, const char **argv)
1979 {
1980         ADS_STRUCT *ads;
1981         const char *auth_principal = opt_user_name;
1982         const char *auth_password = opt_password;
1983         char *realm = NULL;
1984         char *new_password = NULL;
1985         char *c, *prompt;
1986         const char *user;
1987         ADS_STATUS ret;
1988
1989         if (opt_user_name == NULL || opt_password == NULL) {
1990                 d_fprintf(stderr, "You must supply an administrator username/password\n");
1991                 return -1;
1992         }
1993
1994         if (argc < 1) {
1995                 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1996                 return -1;
1997         }
1998
1999         user = argv[0];
2000         if (!strchr_m(user, '@')) {
2001                 asprintf(&c, "%s@%s", argv[0], lp_realm());
2002                 user = c;
2003         }
2004
2005         use_in_memory_ccache();    
2006         c = strchr_m(auth_principal, '@');
2007         if (c) {
2008                 realm = ++c;
2009         } else {
2010                 realm = lp_realm();
2011         }
2012
2013         /* use the realm so we can eventually change passwords for users 
2014         in realms other than default */
2015         if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
2016                 return -1;
2017         }
2018
2019         /* we don't actually need a full connect, but it's the easy way to
2020                 fill in the KDC's addresss */
2021         ads_connect(ads);
2022     
2023         if (!ads || !ads->config.realm) {
2024                 d_fprintf(stderr, "Didn't find the kerberos server!\n");
2025                 return -1;
2026         }
2027
2028         if (argv[1]) {
2029                 new_password = (char *)argv[1];
2030         } else {
2031                 asprintf(&prompt, "Enter new password for %s:", user);
2032                 new_password = getpass(prompt);
2033                 free(prompt);
2034         }
2035
2036         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
2037                                 auth_password, user, new_password, ads->auth.time_offset);
2038         if (!ADS_ERR_OK(ret)) {
2039                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2040                 ads_destroy(&ads);
2041                 return -1;
2042         }
2043
2044         d_printf("Password change for %s completed.\n", user);
2045         ads_destroy(&ads);
2046
2047         return 0;
2048 }
2049
2050 int net_ads_changetrustpw(int argc, const char **argv)
2051 {    
2052         ADS_STRUCT *ads;
2053         char *host_principal;
2054         fstring my_name;
2055         ADS_STATUS ret;
2056
2057         if (!secrets_init()) {
2058                 DEBUG(1,("Failed to initialise secrets database\n"));
2059                 return -1;
2060         }
2061
2062         net_use_machine_password();
2063
2064         use_in_memory_ccache();
2065
2066         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2067                 return -1;
2068         }
2069
2070         fstrcpy(my_name, global_myname());
2071         strlower_m(my_name);
2072         asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
2073         d_printf("Changing password for principal: %s\n", host_principal);
2074
2075         ret = ads_change_trust_account_password(ads, host_principal);
2076
2077         if (!ADS_ERR_OK(ret)) {
2078                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2079                 ads_destroy(&ads);
2080                 SAFE_FREE(host_principal);
2081                 return -1;
2082         }
2083     
2084         d_printf("Password change for principal %s succeeded.\n", host_principal);
2085
2086         if (lp_use_kerberos_keytab()) {
2087                 d_printf("Attempting to update system keytab with new password.\n");
2088                 if (ads_keytab_create_default(ads)) {
2089                         d_printf("Failed to update system keytab.\n");
2090                 }
2091         }
2092
2093         ads_destroy(&ads);
2094         SAFE_FREE(host_principal);
2095
2096         return 0;
2097 }
2098
2099 /*
2100   help for net ads search
2101 */
2102 static int net_ads_search_usage(int argc, const char **argv)
2103 {
2104         d_printf(
2105                 "\nnet ads search <expression> <attributes...>\n"\
2106                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2107                 "The expression is a standard LDAP search expression, and the\n"\
2108                 "attributes are a list of LDAP fields to show in the results\n\n"\
2109                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2110                 );
2111         net_common_flags_usage(argc, argv);
2112         return -1;
2113 }
2114
2115
2116 /*
2117   general ADS search function. Useful in diagnosing problems in ADS
2118 */
2119 static int net_ads_search(int argc, const char **argv)
2120 {
2121         ADS_STRUCT *ads;
2122         ADS_STATUS rc;
2123         const char *ldap_exp;
2124         const char **attrs;
2125         LDAPMessage *res = NULL;
2126
2127         if (argc < 1) {
2128                 return net_ads_search_usage(argc, argv);
2129         }
2130
2131         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2132                 return -1;
2133         }
2134
2135         ldap_exp = argv[0];
2136         attrs = (argv + 1);
2137
2138         rc = ads_do_search_all(ads, ads->config.bind_path,
2139                                LDAP_SCOPE_SUBTREE,
2140                                ldap_exp, attrs, &res);
2141         if (!ADS_ERR_OK(rc)) {
2142                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2143                 ads_destroy(&ads);
2144                 return -1;
2145         }       
2146
2147         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2148
2149         /* dump the results */
2150         ads_dump(ads, res);
2151
2152         ads_msgfree(ads, res);
2153         ads_destroy(&ads);
2154
2155         return 0;
2156 }
2157
2158
2159 /*
2160   help for net ads search
2161 */
2162 static int net_ads_dn_usage(int argc, const char **argv)
2163 {
2164         d_printf(
2165                 "\nnet ads dn <dn> <attributes...>\n"\
2166                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2167                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
2168                 "to show in the results\n\n"\
2169                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2170                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2171                 );
2172         net_common_flags_usage(argc, argv);
2173         return -1;
2174 }
2175
2176
2177 /*
2178   general ADS search function. Useful in diagnosing problems in ADS
2179 */
2180 static int net_ads_dn(int argc, const char **argv)
2181 {
2182         ADS_STRUCT *ads;
2183         ADS_STATUS rc;
2184         const char *dn;
2185         const char **attrs;
2186         LDAPMessage *res = NULL;
2187
2188         if (argc < 1) {
2189                 return net_ads_dn_usage(argc, argv);
2190         }
2191
2192         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2193                 return -1;
2194         }
2195
2196         dn = argv[0];
2197         attrs = (argv + 1);
2198
2199         rc = ads_do_search_all(ads, dn, 
2200                                LDAP_SCOPE_BASE,
2201                                "(objectclass=*)", attrs, &res);
2202         if (!ADS_ERR_OK(rc)) {
2203                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2204                 ads_destroy(&ads);
2205                 return -1;
2206         }       
2207
2208         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2209
2210         /* dump the results */
2211         ads_dump(ads, res);
2212
2213         ads_msgfree(ads, res);
2214         ads_destroy(&ads);
2215
2216         return 0;
2217 }
2218
2219 /*
2220   help for net ads sid search
2221 */
2222 static int net_ads_sid_usage(int argc, const char **argv)
2223 {
2224         d_printf(
2225                 "\nnet ads sid <sid> <attributes...>\n"\
2226                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2227                 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
2228                 "to show in the results\n\n"\
2229                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2230                 );
2231         net_common_flags_usage(argc, argv);
2232         return -1;
2233 }
2234
2235
2236 /*
2237   general ADS search function. Useful in diagnosing problems in ADS
2238 */
2239 static int net_ads_sid(int argc, const char **argv)
2240 {
2241         ADS_STRUCT *ads;
2242         ADS_STATUS rc;
2243         const char *sid_string;
2244         const char **attrs;
2245         LDAPMessage *res = NULL;
2246         DOM_SID sid;
2247
2248         if (argc < 1) {
2249                 return net_ads_sid_usage(argc, argv);
2250         }
2251
2252         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2253                 return -1;
2254         }
2255
2256         sid_string = argv[0];
2257         attrs = (argv + 1);
2258
2259         if (!string_to_sid(&sid, sid_string)) {
2260                 d_fprintf(stderr, "could not convert sid\n");
2261                 ads_destroy(&ads);
2262                 return -1;
2263         }
2264
2265         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2266         if (!ADS_ERR_OK(rc)) {
2267                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2268                 ads_destroy(&ads);
2269                 return -1;
2270         }       
2271
2272         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2273
2274         /* dump the results */
2275         ads_dump(ads, res);
2276
2277         ads_msgfree(ads, res);
2278         ads_destroy(&ads);
2279
2280         return 0;
2281 }
2282
2283
2284 static int net_ads_keytab_usage(int argc, const char **argv)
2285 {
2286         d_printf(
2287                 "net ads keytab <COMMAND>\n"\
2288 "<COMMAND> can be either:\n"\
2289 "  CREATE    Creates a fresh keytab\n"\
2290 "  ADD       Adds new service principal\n"\
2291 "  FLUSH     Flushes out all keytab entries\n"\
2292 "  HELP      Prints this help message\n"\
2293 "The ADD command will take arguments, the other commands\n"\
2294 "will not take any arguments.   The arguments given to ADD\n"\
2295 "should be a list of principals to add.  For example, \n"\
2296 "   net ads keytab add srv1 srv2\n"\
2297 "will add principals for the services srv1 and srv2 to the\n"\
2298 "system's keytab.\n"\
2299 "\n"
2300                 );
2301         return -1;
2302 }
2303
2304 static int net_ads_keytab_flush(int argc, const char **argv)
2305 {
2306         int ret;
2307         ADS_STRUCT *ads;
2308
2309         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2310                 return -1;
2311         }
2312         ret = ads_keytab_flush(ads);
2313         ads_destroy(&ads);
2314         return ret;
2315 }
2316
2317 static int net_ads_keytab_add(int argc, const char **argv)
2318 {
2319         int i;
2320         int ret = 0;
2321         ADS_STRUCT *ads;
2322
2323         d_printf("Processing principals to add...\n");
2324         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2325                 return -1;
2326         }
2327         for (i = 0; i < argc; i++) {
2328                 ret |= ads_keytab_add_entry(ads, argv[i]);
2329         }
2330         ads_destroy(&ads);
2331         return ret;
2332 }
2333
2334 static int net_ads_keytab_create(int argc, const char **argv)
2335 {
2336         ADS_STRUCT *ads;
2337         int ret;
2338
2339         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2340                 return -1;
2341         }
2342         ret = ads_keytab_create_default(ads);
2343         ads_destroy(&ads);
2344         return ret;
2345 }
2346
2347 int net_ads_keytab(int argc, const char **argv)
2348 {
2349         struct functable func[] = {
2350                 {"CREATE", net_ads_keytab_create},
2351                 {"ADD", net_ads_keytab_add},
2352                 {"FLUSH", net_ads_keytab_flush},
2353                 {"HELP", net_ads_keytab_usage},
2354                 {NULL, NULL}
2355         };
2356
2357         if (!lp_use_kerberos_keytab()) {
2358                 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2359 use keytab functions.\n");
2360         }
2361
2362         return net_run_function(argc, argv, func, net_ads_keytab_usage);
2363 }
2364
2365 int net_ads_help(int argc, const char **argv)
2366 {
2367         struct functable func[] = {
2368                 {"USER", net_ads_user_usage},
2369                 {"GROUP", net_ads_group_usage},
2370                 {"PRINTER", net_ads_printer_usage},
2371                 {"SEARCH", net_ads_search_usage},
2372                 {"INFO", net_ads_info},
2373                 {"JOIN", net_ads_join_usage},
2374                 {"DNS", net_ads_dns_usage},
2375                 {"LEAVE", net_ads_leave},
2376                 {"STATUS", net_ads_status},
2377                 {"PASSWORD", net_ads_password},
2378                 {"CHANGETRUSTPW", net_ads_changetrustpw},
2379                 {NULL, NULL}
2380         };
2381
2382         return net_run_function(argc, argv, func, net_ads_usage);
2383 }
2384
2385 int net_ads(int argc, const char **argv)
2386 {
2387         struct functable func[] = {
2388                 {"INFO", net_ads_info},
2389                 {"JOIN", net_ads_join},
2390                 {"TESTJOIN", net_ads_testjoin},
2391                 {"LEAVE", net_ads_leave},
2392                 {"STATUS", net_ads_status},
2393                 {"USER", net_ads_user},
2394                 {"GROUP", net_ads_group},
2395                 {"DNS", net_ads_dns},
2396                 {"PASSWORD", net_ads_password},
2397                 {"CHANGETRUSTPW", net_ads_changetrustpw},
2398                 {"PRINTER", net_ads_printer},
2399                 {"SEARCH", net_ads_search},
2400                 {"DN", net_ads_dn},
2401                 {"SID", net_ads_sid},
2402                 {"WORKGROUP", net_ads_workgroup},
2403                 {"LOOKUP", net_ads_lookup},
2404                 {"KEYTAB", net_ads_keytab},
2405                 {"GPO", net_ads_gpo},
2406                 {"HELP", net_ads_help},
2407                 {NULL, NULL}
2408         };
2409         
2410         return net_run_function(argc, argv, func, net_ads_usage);
2411 }
2412
2413 #else
2414
2415 static int net_ads_noads(void)
2416 {
2417         d_fprintf(stderr, "ADS support not compiled in\n");
2418         return -1;
2419 }
2420
2421 int net_ads_keytab(int argc, const char **argv)
2422 {
2423         return net_ads_noads();
2424 }
2425
2426 int net_ads_usage(int argc, const char **argv)
2427 {
2428         return net_ads_noads();
2429 }
2430
2431 int net_ads_help(int argc, const char **argv)
2432 {
2433         return net_ads_noads();
2434 }
2435
2436 int net_ads_changetrustpw(int argc, const char **argv)
2437 {
2438         return net_ads_noads();
2439 }
2440
2441 int net_ads_join(int argc, const char **argv)
2442 {
2443         return net_ads_noads();
2444 }
2445
2446 int net_ads_user(int argc, const char **argv)
2447 {
2448         return net_ads_noads();
2449 }
2450
2451 int net_ads_group(int argc, const char **argv)
2452 {
2453         return net_ads_noads();
2454 }
2455
2456 /* this one shouldn't display a message */
2457 int net_ads_check(void)
2458 {
2459         return -1;
2460 }
2461
2462 int net_ads_check_our_domain(void)
2463 {
2464         return -1;
2465 }
2466
2467 int net_ads(int argc, const char **argv)
2468 {
2469         return net_ads_usage(argc, argv);
2470 }
2471
2472 #endif  /* WITH_ADS */