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