The usual !pstring...
[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", 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         LDAPMessage *res = NULL;
1259         const char *machine_name = global_myname();
1260
1261         status = ads_domain_func_level( ads, &domain_func );
1262         if ( !ADS_ERR_OK(status) ) {
1263                 DEBUG(2,("Failed to determine domain functional level!\n"));
1264                 return False;
1265         }
1266
1267         /* go ahead and setup the default salt */
1268
1269         if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
1270                 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
1271                 return False;
1272         }
1273
1274         fstrcpy( salt, std_salt );
1275         SAFE_FREE( std_salt );
1276
1277         /* if it's a Windows functional domain, we have to look for the UPN */
1278
1279         if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) {
1280                 char *upn;
1281                 int count;
1282
1283                 status = ads_find_machine_acct(ads, &res, machine_name);
1284                 if (!ADS_ERR_OK(status)) {
1285                         return False;
1286                 }
1287
1288                 if ( (count = ads_count_replies(ads, res)) != 1 ) {
1289                         DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1290                         return False;
1291                 }
1292
1293                 upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
1294                 if ( upn ) {
1295                         fstrcpy( salt, upn );
1296                 }
1297
1298                 ads_msgfree(ads, res);
1299         }
1300
1301         return kerberos_secrets_store_des_salt( salt );
1302 }
1303
1304 /*******************************************************************
1305  Send a DNS update request
1306 *******************************************************************/
1307
1308 #if defined(WITH_DNS_UPDATES)
1309 #include "dns.h"
1310 DNS_ERROR DoDNSUpdate(char *pszServerName,
1311                       const char *pszDomainName,
1312                       const char *pszHostName,
1313                       const struct in_addr *iplist, int num_addrs );
1314
1315
1316 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1317                                         const char *machine_name,
1318                                         const struct in_addr *addrs,
1319                                         int num_addrs)
1320 {
1321         struct dns_rr_ns *nameservers = NULL;
1322         int ns_count = 0;
1323         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1324         DNS_ERROR dns_err;
1325         fstring dns_server;
1326         const char *dnsdomain = NULL;
1327         char *root_domain = NULL;
1328
1329         if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1330                 d_printf("No DNS domain configured for %s. "
1331                          "Unable to perform DNS Update.\n", machine_name);
1332                 status = NT_STATUS_INVALID_PARAMETER;
1333                 goto done;
1334         }
1335         dnsdomain++;
1336
1337         status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1338         if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1339                 /* Child domains often do not have NS records.  Look
1340                    for the NS record for the forest root domain
1341                    (rootDomainNamingContext in therootDSE) */
1342
1343                 const char *rootname_attrs[] =  { "rootDomainNamingContext", NULL };
1344                 LDAPMessage *msg = NULL;
1345                 char *root_dn;
1346                 ADS_STATUS ads_status;
1347
1348                 if ( !ads->ldap.ld ) {
1349                         ads_status = ads_connect( ads );
1350                         if ( !ADS_ERR_OK(ads_status) ) {
1351                                 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1352                                 goto done;
1353                         }
1354                 }
1355
1356                 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1357                                        "(objectclass=*)", rootname_attrs, &msg);
1358                 if (!ADS_ERR_OK(ads_status)) {
1359                         goto done;
1360                 }
1361
1362                 root_dn = ads_pull_string(ads, ctx, msg,  "rootDomainNamingContext");
1363                 if ( !root_dn ) {
1364                         ads_msgfree( ads, msg );
1365                         goto done;
1366                 }
1367
1368                 root_domain = ads_build_domain( root_dn );
1369
1370                 /* cleanup */
1371                 ads_msgfree( ads, msg );
1372
1373                 /* try again for NS servers */
1374
1375                 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1376
1377                 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1378                         DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1379                          "realm\n", ads->config.realm));
1380                         goto done;
1381                 }
1382
1383                 dnsdomain = root_domain;
1384
1385         }
1386
1387         /* Now perform the dns update - we'll try non-secure and if we fail,
1388            we'll follow it up with a secure update */
1389
1390         fstrcpy( dns_server, nameservers[0].hostname );
1391
1392         dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1393         if (!ERR_DNS_IS_OK(dns_err)) {
1394                 status = NT_STATUS_UNSUCCESSFUL;
1395         }
1396
1397 done:
1398
1399         SAFE_FREE( root_domain );
1400
1401         return status;
1402 }
1403
1404 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1405 {
1406         int num_addrs;
1407         struct in_addr *iplist = NULL;
1408         fstring machine_name;
1409         NTSTATUS status;
1410
1411         name_to_fqdn( machine_name, global_myname() );
1412         strlower_m( machine_name );
1413
1414         /* Get our ip address (not the 127.0.0.x address but a real ip
1415          * address) */
1416
1417         num_addrs = get_my_ip_address( &iplist );
1418         if ( num_addrs <= 0 ) {
1419                 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1420                          "addresses!\n"));
1421                 return NT_STATUS_INVALID_PARAMETER;
1422         }
1423
1424         status = net_update_dns_internal(mem_ctx, ads, machine_name,
1425                                          iplist, num_addrs);
1426         SAFE_FREE( iplist );
1427         return status;
1428 }
1429 #endif
1430
1431
1432 /*******************************************************************
1433  ********************************************************************/
1434
1435 static int net_ads_join_usage(int argc, const char **argv)
1436 {
1437         d_printf("net ads join [options]\n");
1438         d_printf("Valid options:\n");
1439         d_printf("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n");
1440         d_printf("                      The deault UPN is in the form host/netbiosname@REALM.\n");
1441         d_printf("   createcomputer=OU  Precreate the computer account in a specific OU.\n");
1442         d_printf("                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1443         d_printf("                      E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1444         d_printf("                      NB: A backslash '\\' is used as escape at multiple levels and may\n");
1445         d_printf("                          need to be doubled or even quadrupled.  It is not used as a separator.\n");
1446         d_printf("   osName=string      Set the operatingSystem attribute during the join.\n");
1447         d_printf("   osVer=string       Set the operatingSystemVersion attribute during the join.\n");
1448         d_printf("                      NB: osName and osVer must be specified together for either to take effect.\n");
1449         d_printf("                          Also, the operatingSystemService attribute is also set when along with\n");
1450         d_printf("                          the two other attributes.\n");
1451
1452         return -1;
1453 }
1454
1455 /*******************************************************************
1456  ********************************************************************/
1457
1458 int net_ads_join(int argc, const char **argv)
1459 {
1460         ADS_STRUCT *ads = NULL;
1461         ADS_STATUS status;
1462         NTSTATUS nt_status;
1463         char *machine_account = NULL;
1464         char *short_domain_name = NULL;
1465         char *tmp_password, *password;
1466         TALLOC_CTX *ctx = NULL;
1467         DOM_SID *domain_sid = NULL;
1468         bool createupn = False;
1469         const char *machineupn = NULL;
1470         const char *create_in_ou = NULL;
1471         int i;
1472         fstring dc_name;
1473         struct sockaddr_storage dcss;
1474         const char *os_name = NULL;
1475         const char *os_version = NULL;
1476
1477         nt_status = check_ads_config();
1478         if (!NT_STATUS_IS_OK(nt_status)) {
1479                 d_fprintf(stderr, "Invalid configuration.  Exiting....\n");
1480                 goto fail;
1481         }
1482
1483         /* find a DC to initialize the server affinity cache */
1484
1485         get_dc_name( lp_workgroup(), lp_realm(), dc_name, &dcss );
1486
1487         status = ads_startup(True, &ads);
1488         if (!ADS_ERR_OK(status)) {
1489                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1490                 nt_status = ads_ntstatus(status);
1491                 goto fail;
1492         }
1493
1494         if (strcmp(ads->config.realm, lp_realm()) != 0) {
1495                 d_fprintf(stderr, "realm of remote server (%s) and realm in %s "
1496                         "(%s) DO NOT match.  Aborting join\n",
1497                         ads->config.realm, dyn_CONFIGFILE, lp_realm());
1498                 nt_status = NT_STATUS_INVALID_PARAMETER;
1499                 goto fail;
1500         }
1501
1502         if (!(ctx = talloc_init("net_ads_join"))) {
1503                 d_fprintf(stderr, "Could not initialise talloc context.\n");
1504                 nt_status = NT_STATUS_NO_MEMORY;
1505                 goto fail;
1506         }
1507
1508         /* process additional command line args */
1509
1510         for ( i=0; i<argc; i++ ) {
1511                 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1512                         createupn = True;
1513                         machineupn = get_string_param(argv[i]);
1514                 }
1515                 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1516                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1517                                 d_fprintf(stderr, "Please supply a valid OU path.\n");
1518                                 nt_status = NT_STATUS_INVALID_PARAMETER;
1519                                 goto fail;
1520                         }
1521                 }
1522                 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1523                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1524                                 d_fprintf(stderr, "Please supply a operating system name.\n");
1525                                 nt_status = NT_STATUS_INVALID_PARAMETER;
1526                                 goto fail;
1527                         }
1528                 }
1529                 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1530                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1531                                 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1532                                 nt_status = NT_STATUS_INVALID_PARAMETER;
1533                                 goto fail;
1534                         }
1535                 }
1536                 else {
1537                         d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1538                         nt_status = NT_STATUS_INVALID_PARAMETER;
1539                         goto fail;
1540                 }
1541         }
1542
1543         /* If we were given an OU, try to create the machine in
1544            the OU account first and then do the normal RPC join */
1545
1546         if  ( create_in_ou ) {
1547                 status = net_precreate_machine_acct( ads, create_in_ou );
1548                 if ( !ADS_ERR_OK(status) ) {
1549                         d_fprintf( stderr, "Failed to pre-create the machine object "
1550                                 "in OU %s.\n", create_in_ou);
1551                         DEBUG(1, ("error calling net_precreate_machine_acct: %s\n", 
1552                                   ads_errstr(status)));
1553                         nt_status = ads_ntstatus(status);
1554                         goto fail;
1555                 }
1556         }
1557
1558         /* Do the domain join here */
1559
1560         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1561         password = talloc_strdup(ctx, tmp_password);
1562
1563         nt_status = net_join_domain(ctx, ads->config.ldap_server_name,
1564                                     &ads->ldap.ss, &short_domain_name, &domain_sid, password);
1565         if ( !NT_STATUS_IS_OK(nt_status) ) {
1566                 DEBUG(1, ("call of net_join_domain failed: %s\n",
1567                           get_friendly_nt_error_msg(nt_status)));
1568                 goto fail;
1569         }
1570
1571         /* Check the short name of the domain */
1572
1573         if ( !strequal(lp_workgroup(), short_domain_name) ) {
1574                 d_printf("The workgroup in %s does not match the short\n", dyn_CONFIGFILE);
1575                 d_printf("domain name obtained from the server.\n");
1576                 d_printf("Using the name [%s] from the server.\n", short_domain_name);
1577                 d_printf("You should set \"workgroup = %s\" in %s.\n",
1578                          short_domain_name, dyn_CONFIGFILE);
1579         }
1580
1581         d_printf("Using short domain name -- %s\n", short_domain_name);
1582
1583         /*  HACK ALERT!  Store the sid and password under both the lp_workgroup() 
1584             value from smb.conf and the string returned from the server.  The former is
1585             neede to bootstrap winbindd's first connection to the DC to get the real 
1586             short domain name   --jerry */
1587
1588         if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
1589                 || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
1590         {
1591                 /* issue an internal error here for now.
1592                  * everything else would mean changing tdb routines. */
1593                 nt_status = NT_STATUS_INTERNAL_ERROR;
1594                 goto fail;
1595         }
1596
1597         /* Verify that everything is ok */
1598
1599         nt_status = net_rpc_join_ok(short_domain_name,
1600                                     ads->config.ldap_server_name, &ads->ldap.ss);
1601         if (!NT_STATUS_IS_OK(nt_status)) {
1602                 d_fprintf(stderr,
1603                           "Failed to verify membership in domain: %s!\n",
1604                           nt_errstr(nt_status));
1605                 goto fail;
1606         }
1607
1608         /* create the dNSHostName & servicePrincipalName values */
1609
1610         status = net_set_machine_spn( ctx, ads );
1611         if ( !ADS_ERR_OK(status) )  {
1612
1613                 d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
1614                 d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
1615                 d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
1616
1617                 /* Disable the machine account in AD.  Better to fail than to leave 
1618                    a confused admin.  */
1619
1620                 if ( net_ads_leave( 0, NULL ) != 0 ) {
1621                         d_fprintf( stderr, "Failed to disable machine account in AD.  Please do so manually.\n");
1622                 }
1623
1624                 /* clear out the machine password */
1625
1626                 netdom_store_machine_account( lp_workgroup(), domain_sid, "" );
1627                 netdom_store_machine_account( short_domain_name, domain_sid, "" );
1628
1629                 nt_status = ads_ntstatus(status);
1630                 goto fail;
1631         }
1632
1633         if ( !net_derive_salting_principal( ctx, ads ) ) {
1634                 DEBUG(1,("Failed to determine salting principal\n"));
1635                 goto fail;
1636         }
1637
1638         if ( createupn ) {
1639                 char *upn;
1640
1641                 /* default to using the short UPN name */
1642                 if (!machineupn ) {
1643                         upn = talloc_asprintf(ctx,
1644                                         "host/%s@%s", global_myname(),
1645                                         ads->config.realm );
1646                         if (!upn) {
1647                                 nt_status = NT_STATUS_NO_MEMORY;
1648                                 goto fail;
1649                         }
1650                         machineupn = upn;
1651                 }
1652
1653                 status = net_set_machine_upn( ctx, ads, machineupn );
1654                 if ( !ADS_ERR_OK(status) )  {
1655                         d_fprintf(stderr, "Failed to set userPrincipalName.  Are you a Domain Admin?\n");
1656                 }
1657         }
1658
1659         /* Try to set the operatingSystem attributes if asked */
1660
1661         if ( os_name && os_version ) {
1662                 status = net_set_os_attributes( ctx, ads, os_name, os_version );
1663                 if ( !ADS_ERR_OK(status) )  {
1664                         d_fprintf(stderr, "Failed to set operatingSystem attributes.  "
1665                                   "Are you a Domain Admin?\n");
1666                 }
1667         }
1668
1669         /* Now build the keytab, using the same ADS connection */
1670
1671         if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
1672                 DEBUG(1,("Error creating host keytab!\n"));
1673         }
1674
1675 #if defined(WITH_DNS_UPDATES)
1676         /* We enter this block with user creds */
1677         ads_kdestroy( NULL );
1678         ads_destroy(&ads);
1679         ads = NULL;
1680
1681         if ( (ads = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1682                 /* kinit with the machine password */
1683
1684                 use_in_memory_ccache();
1685                 asprintf( &ads->auth.user_name, "%s$", global_myname() );
1686                 ads->auth.password = secrets_fetch_machine_password(
1687                         lp_workgroup(), NULL, NULL );
1688                 ads->auth.realm = SMB_STRDUP( lp_realm() );
1689                 ads_kinit_password( ads );
1690         }
1691
1692         if ( !ads || !NT_STATUS_IS_OK(net_update_dns( ctx, ads )) ) {
1693                 d_fprintf( stderr, "DNS update failed!\n" );
1694         }
1695
1696         /* exit from this block using machine creds */
1697 #endif
1698
1699         d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->server.realm);
1700
1701         SAFE_FREE(machine_account);
1702         TALLOC_FREE( ctx );
1703         ads_destroy(&ads);
1704
1705         return 0;
1706
1707 fail:
1708         /* issue an overall failure message at the end. */
1709         d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
1710
1711         SAFE_FREE(machine_account);
1712         TALLOC_FREE( ctx );
1713         ads_destroy(&ads);
1714
1715         return -1;
1716
1717 }
1718
1719 /*******************************************************************
1720  ********************************************************************/
1721
1722 static int net_ads_dns_usage(int argc, const char **argv)
1723 {
1724 #if defined(WITH_DNS_UPDATES)
1725         d_printf("net ads dns <command>\n");
1726         d_printf("Valid commands:\n");
1727         d_printf("   register         Issue a dynamic DNS update request for our hostname\n");
1728
1729         return 0;
1730 #else
1731         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1732         return -1;
1733 #endif
1734 }
1735
1736 /*******************************************************************
1737  ********************************************************************/
1738
1739 static int net_ads_dns_register(int argc, const char **argv)
1740 {
1741 #if defined(WITH_DNS_UPDATES)
1742         ADS_STRUCT *ads;
1743         ADS_STATUS status;
1744         TALLOC_CTX *ctx;
1745
1746 #ifdef DEVELOPER
1747         talloc_enable_leak_report();
1748 #endif
1749
1750         if (argc > 0) {
1751                 d_fprintf(stderr, "net ads dns register\n");
1752                 return -1;
1753         }
1754
1755         if (!(ctx = talloc_init("net_ads_dns"))) {
1756                 d_fprintf(stderr, "Could not initialise talloc context\n");
1757                 return -1;
1758         }
1759
1760         status = ads_startup(True, &ads);
1761         if ( !ADS_ERR_OK(status) ) {
1762                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1763                 TALLOC_FREE(ctx);
1764                 return -1;
1765         }
1766
1767         if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1768                 d_fprintf( stderr, "DNS update failed!\n" );
1769                 ads_destroy( &ads );
1770                 TALLOC_FREE( ctx );
1771                 return -1;
1772         }
1773
1774         d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1775
1776         ads_destroy(&ads);
1777         TALLOC_FREE( ctx );
1778
1779         return 0;
1780 #else
1781         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1782         return -1;
1783 #endif
1784 }
1785
1786 #if defined(WITH_DNS_UPDATES)
1787 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1788 #endif
1789
1790 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1791 {
1792 #if defined(WITH_DNS_UPDATES)
1793         DNS_ERROR err;
1794
1795 #ifdef DEVELOPER
1796         talloc_enable_leak_report();
1797 #endif
1798
1799         if (argc != 2) {
1800                 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1801                           "<name>\n");
1802                 return -1;
1803         }
1804
1805         err = do_gethostbyname(argv[0], argv[1]);
1806
1807         d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1808 #endif
1809         return 0;
1810 }
1811
1812 static int net_ads_dns(int argc, const char *argv[])
1813 {
1814         struct functable func[] = {
1815                 {"REGISTER", net_ads_dns_register},
1816                 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1817                 {NULL, NULL}
1818         };
1819
1820         return net_run_function(argc, argv, func, net_ads_dns_usage);
1821 }
1822
1823 /*******************************************************************
1824  ********************************************************************/
1825
1826 int net_ads_printer_usage(int argc, const char **argv)
1827 {
1828         d_printf(
1829 "\nnet ads printer search <printer>"
1830 "\n\tsearch for a printer in the directory\n"
1831 "\nnet ads printer info <printer> <server>"
1832 "\n\tlookup info in directory for printer on server"
1833 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1834 "\nnet ads printer publish <printername>"
1835 "\n\tpublish printer in directory"
1836 "\n\t(note: printer name is required)\n"
1837 "\nnet ads printer remove <printername>"
1838 "\n\tremove printer from directory"
1839 "\n\t(note: printer name is required)\n");
1840         return -1;
1841 }
1842
1843 /*******************************************************************
1844  ********************************************************************/
1845
1846 static int net_ads_printer_search(int argc, const char **argv)
1847 {
1848         ADS_STRUCT *ads;
1849         ADS_STATUS rc;
1850         LDAPMessage *res = NULL;
1851
1852         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1853                 return -1;
1854         }
1855
1856         rc = ads_find_printers(ads, &res);
1857
1858         if (!ADS_ERR_OK(rc)) {
1859                 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1860                 ads_msgfree(ads, res);
1861                 ads_destroy(&ads);
1862                 return -1;
1863         }
1864
1865         if (ads_count_replies(ads, res) == 0) {
1866                 d_fprintf(stderr, "No results found\n");
1867                 ads_msgfree(ads, res);
1868                 ads_destroy(&ads);
1869                 return -1;
1870         }
1871
1872         ads_dump(ads, res);
1873         ads_msgfree(ads, res);
1874         ads_destroy(&ads);
1875         return 0;
1876 }
1877
1878 static int net_ads_printer_info(int argc, const char **argv)
1879 {
1880         ADS_STRUCT *ads;
1881         ADS_STATUS rc;
1882         const char *servername, *printername;
1883         LDAPMessage *res = NULL;
1884
1885         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1886                 return -1;
1887         }
1888
1889         if (argc > 0) {
1890                 printername = argv[0];
1891         } else {
1892                 printername = "*";
1893         }
1894
1895         if (argc > 1) {
1896                 servername =  argv[1];
1897         } else {
1898                 servername = global_myname();
1899         }
1900
1901         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1902
1903         if (!ADS_ERR_OK(rc)) {
1904                 d_fprintf(stderr, "Server '%s' not found: %s\n",
1905                         servername, ads_errstr(rc));
1906                 ads_msgfree(ads, res);
1907                 ads_destroy(&ads);
1908                 return -1;
1909         }
1910
1911         if (ads_count_replies(ads, res) == 0) {
1912                 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1913                 ads_msgfree(ads, res);
1914                 ads_destroy(&ads);
1915                 return -1;
1916         }
1917
1918         ads_dump(ads, res);
1919         ads_msgfree(ads, res);
1920         ads_destroy(&ads);
1921
1922         return 0;
1923 }
1924
1925 static int net_ads_printer_publish(int argc, const char **argv)
1926 {
1927         ADS_STRUCT *ads;
1928         ADS_STATUS rc;
1929         const char *servername, *printername;
1930         struct cli_state *cli;
1931         struct rpc_pipe_client *pipe_hnd;
1932         struct sockaddr_storage server_ss;
1933         NTSTATUS nt_status;
1934         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1935         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1936         char *prt_dn, *srv_dn, **srv_cn;
1937         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1938         LDAPMessage *res = NULL;
1939
1940         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1941                 talloc_destroy(mem_ctx);
1942                 return -1;
1943         }
1944
1945         if (argc < 1) {
1946                 talloc_destroy(mem_ctx);
1947                 return net_ads_printer_usage(argc, argv);
1948         }
1949
1950         printername = argv[0];
1951
1952         if (argc == 2) {
1953                 servername = argv[1];
1954         } else {
1955                 servername = global_myname();
1956         }
1957
1958         /* Get printer data from SPOOLSS */
1959
1960         resolve_name(servername, &server_ss, 0x20);
1961
1962         nt_status = cli_full_connection(&cli, global_myname(), servername,
1963                                         &server_ss, 0,
1964                                         "IPC$", "IPC",
1965                                         opt_user_name, opt_workgroup,
1966                                         opt_password ? opt_password : "",
1967                                         CLI_FULL_CONNECTION_USE_KERBEROS,
1968                                         Undefined, NULL);
1969
1970         if (NT_STATUS_IS_ERR(nt_status)) {
1971                 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1972                          "for %s\n", servername, printername);
1973                 ads_destroy(&ads);
1974                 talloc_destroy(mem_ctx);
1975                 return -1;
1976         }
1977
1978         /* Publish on AD server */
1979
1980         ads_find_machine_acct(ads, &res, servername);
1981
1982         if (ads_count_replies(ads, res) == 0) {
1983                 d_fprintf(stderr, "Could not find machine account for server %s\n", 
1984                          servername);
1985                 ads_destroy(&ads);
1986                 talloc_destroy(mem_ctx);
1987                 return -1;
1988         }
1989
1990         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1991         srv_cn = ldap_explode_dn(srv_dn, 1);
1992
1993         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1994         printername_escaped = escape_rdn_val_string_alloc(printername);
1995         if (!srv_cn_escaped || !printername_escaped) {
1996                 SAFE_FREE(srv_cn_escaped);
1997                 SAFE_FREE(printername_escaped);
1998                 d_fprintf(stderr, "Internal error, out of memory!");
1999                 ads_destroy(&ads);
2000                 talloc_destroy(mem_ctx);
2001                 return -1;
2002         }
2003
2004         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
2005
2006         SAFE_FREE(srv_cn_escaped);
2007         SAFE_FREE(printername_escaped);
2008
2009         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
2010         if (!pipe_hnd) {
2011                 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
2012                          servername);
2013                 SAFE_FREE(prt_dn);
2014                 ads_destroy(&ads);
2015                 talloc_destroy(mem_ctx);
2016                 return -1;
2017         }
2018
2019         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2020                                                               printername))) {
2021                 SAFE_FREE(prt_dn);
2022                 ads_destroy(&ads);
2023                 talloc_destroy(mem_ctx);
2024                 return -1;
2025         }
2026
2027         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2028         if (!ADS_ERR_OK(rc)) {
2029                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2030                 SAFE_FREE(prt_dn);
2031                 ads_destroy(&ads);
2032                 talloc_destroy(mem_ctx);
2033                 return -1;
2034         }
2035
2036         d_printf("published printer\n");
2037         SAFE_FREE(prt_dn);
2038         ads_destroy(&ads);
2039         talloc_destroy(mem_ctx);
2040
2041         return 0;
2042 }
2043
2044 static int net_ads_printer_remove(int argc, const char **argv)
2045 {
2046         ADS_STRUCT *ads;
2047         ADS_STATUS rc;
2048         const char *servername;
2049         char *prt_dn;
2050         LDAPMessage *res = NULL;
2051
2052         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2053                 return -1;
2054         }
2055
2056         if (argc < 1) {
2057                 return net_ads_printer_usage(argc, argv);
2058         }
2059
2060         if (argc > 1) {
2061                 servername = argv[1];
2062         } else {
2063                 servername = global_myname();
2064         }
2065
2066         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2067
2068         if (!ADS_ERR_OK(rc)) {
2069                 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
2070                 ads_msgfree(ads, res);
2071                 ads_destroy(&ads);
2072                 return -1;
2073         }
2074
2075         if (ads_count_replies(ads, res) == 0) {
2076                 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
2077                 ads_msgfree(ads, res);
2078                 ads_destroy(&ads);
2079                 return -1;
2080         }
2081
2082         prt_dn = ads_get_dn(ads, res);
2083         ads_msgfree(ads, res);
2084         rc = ads_del_dn(ads, prt_dn);
2085         ads_memfree(ads, prt_dn);
2086
2087         if (!ADS_ERR_OK(rc)) {
2088                 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
2089                 ads_destroy(&ads);
2090                 return -1;
2091         }
2092
2093         ads_destroy(&ads);
2094         return 0;
2095 }
2096
2097 static int net_ads_printer(int argc, const char **argv)
2098 {
2099         struct functable func[] = {
2100                 {"SEARCH", net_ads_printer_search},
2101                 {"INFO", net_ads_printer_info},
2102                 {"PUBLISH", net_ads_printer_publish},
2103                 {"REMOVE", net_ads_printer_remove},
2104                 {NULL, NULL}
2105         };
2106
2107         return net_run_function(argc, argv, func, net_ads_printer_usage);
2108 }
2109
2110
2111 static int net_ads_password(int argc, const char **argv)
2112 {
2113         ADS_STRUCT *ads;
2114         const char *auth_principal = opt_user_name;
2115         const char *auth_password = opt_password;
2116         char *realm = NULL;
2117         char *new_password = NULL;
2118         char *c, *prompt;
2119         const char *user;
2120         ADS_STATUS ret;
2121
2122         if (opt_user_name == NULL || opt_password == NULL) {
2123                 d_fprintf(stderr, "You must supply an administrator username/password\n");
2124                 return -1;
2125         }
2126
2127         if (argc < 1) {
2128                 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
2129                 return -1;
2130         }
2131
2132         user = argv[0];
2133         if (!strchr_m(user, '@')) {
2134                 asprintf(&c, "%s@%s", argv[0], lp_realm());
2135                 user = c;
2136         }
2137
2138         use_in_memory_ccache();
2139         c = strchr_m(auth_principal, '@');
2140         if (c) {
2141                 realm = ++c;
2142         } else {
2143                 realm = lp_realm();
2144         }
2145
2146         /* use the realm so we can eventually change passwords for users
2147         in realms other than default */
2148         if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
2149                 return -1;
2150         }
2151
2152         /* we don't actually need a full connect, but it's the easy way to
2153                 fill in the KDC's addresss */
2154         ads_connect(ads);
2155
2156         if (!ads || !ads->config.realm) {
2157                 d_fprintf(stderr, "Didn't find the kerberos server!\n");
2158                 return -1;
2159         }
2160
2161         if (argv[1]) {
2162                 new_password = (char *)argv[1];
2163         } else {
2164                 asprintf(&prompt, "Enter new password for %s:", user);
2165                 new_password = getpass(prompt);
2166                 free(prompt);
2167         }
2168
2169         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2170                                 auth_password, user, new_password, ads->auth.time_offset);
2171         if (!ADS_ERR_OK(ret)) {
2172                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2173                 ads_destroy(&ads);
2174                 return -1;
2175         }
2176
2177         d_printf("Password change for %s completed.\n", user);
2178         ads_destroy(&ads);
2179
2180         return 0;
2181 }
2182
2183 int net_ads_changetrustpw(int argc, const char **argv)
2184 {
2185         ADS_STRUCT *ads;
2186         char *host_principal;
2187         fstring my_name;
2188         ADS_STATUS ret;
2189
2190         if (!secrets_init()) {
2191                 DEBUG(1,("Failed to initialise secrets database\n"));
2192                 return -1;
2193         }
2194
2195         net_use_krb_machine_account();
2196
2197         use_in_memory_ccache();
2198
2199         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2200                 return -1;
2201         }
2202
2203         fstrcpy(my_name, global_myname());
2204         strlower_m(my_name);
2205         asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
2206         d_printf("Changing password for principal: %s\n", host_principal);
2207
2208         ret = ads_change_trust_account_password(ads, host_principal);
2209
2210         if (!ADS_ERR_OK(ret)) {
2211                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2212                 ads_destroy(&ads);
2213                 SAFE_FREE(host_principal);
2214                 return -1;
2215         }
2216
2217         d_printf("Password change for principal %s succeeded.\n", host_principal);
2218
2219         if (lp_use_kerberos_keytab()) {
2220                 d_printf("Attempting to update system keytab with new password.\n");
2221                 if (ads_keytab_create_default(ads)) {
2222                         d_printf("Failed to update system keytab.\n");
2223                 }
2224         }
2225
2226         ads_destroy(&ads);
2227         SAFE_FREE(host_principal);
2228
2229         return 0;
2230 }
2231
2232 /*
2233   help for net ads search
2234 */
2235 static int net_ads_search_usage(int argc, const char **argv)
2236 {
2237         d_printf(
2238                 "\nnet ads search <expression> <attributes...>\n"\
2239                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2240                 "The expression is a standard LDAP search expression, and the\n"\
2241                 "attributes are a list of LDAP fields to show in the results\n\n"\
2242                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2243                 );
2244         net_common_flags_usage(argc, argv);
2245         return -1;
2246 }
2247
2248
2249 /*
2250   general ADS search function. Useful in diagnosing problems in ADS
2251 */
2252 static int net_ads_search(int argc, const char **argv)
2253 {
2254         ADS_STRUCT *ads;
2255         ADS_STATUS rc;
2256         const char *ldap_exp;
2257         const char **attrs;
2258         LDAPMessage *res = NULL;
2259
2260         if (argc < 1) {
2261                 return net_ads_search_usage(argc, argv);
2262         }
2263
2264         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2265                 return -1;
2266         }
2267
2268         ldap_exp = argv[0];
2269         attrs = (argv + 1);
2270
2271         rc = ads_do_search_all(ads, ads->config.bind_path,
2272                                LDAP_SCOPE_SUBTREE,
2273                                ldap_exp, attrs, &res);
2274         if (!ADS_ERR_OK(rc)) {
2275                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2276                 ads_destroy(&ads);
2277                 return -1;
2278         }
2279
2280         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2281
2282         /* dump the results */
2283         ads_dump(ads, res);
2284
2285         ads_msgfree(ads, res);
2286         ads_destroy(&ads);
2287
2288         return 0;
2289 }
2290
2291
2292 /*
2293   help for net ads search
2294 */
2295 static int net_ads_dn_usage(int argc, const char **argv)
2296 {
2297         d_printf(
2298                 "\nnet ads dn <dn> <attributes...>\n"\
2299                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2300                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
2301                 "to show in the results\n\n"\
2302                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2303                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2304                 );
2305         net_common_flags_usage(argc, argv);
2306         return -1;
2307 }
2308
2309
2310 /*
2311   general ADS search function. Useful in diagnosing problems in ADS
2312 */
2313 static int net_ads_dn(int argc, const char **argv)
2314 {
2315         ADS_STRUCT *ads;
2316         ADS_STATUS rc;
2317         const char *dn;
2318         const char **attrs;
2319         LDAPMessage *res = NULL;
2320
2321         if (argc < 1) {
2322                 return net_ads_dn_usage(argc, argv);
2323         }
2324
2325         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2326                 return -1;
2327         }
2328
2329         dn = argv[0];
2330         attrs = (argv + 1);
2331
2332         rc = ads_do_search_all(ads, dn,
2333                                LDAP_SCOPE_BASE,
2334                                "(objectclass=*)", attrs, &res);
2335         if (!ADS_ERR_OK(rc)) {
2336                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2337                 ads_destroy(&ads);
2338                 return -1;
2339         }
2340
2341         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2342
2343         /* dump the results */
2344         ads_dump(ads, res);
2345
2346         ads_msgfree(ads, res);
2347         ads_destroy(&ads);
2348
2349         return 0;
2350 }
2351
2352 /*
2353   help for net ads sid search
2354 */
2355 static int net_ads_sid_usage(int argc, const char **argv)
2356 {
2357         d_printf(
2358                 "\nnet ads sid <sid> <attributes...>\n"\
2359                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2360                 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
2361                 "to show in the results\n\n"\
2362                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2363                 );
2364         net_common_flags_usage(argc, argv);
2365         return -1;
2366 }
2367
2368
2369 /*
2370   general ADS search function. Useful in diagnosing problems in ADS
2371 */
2372 static int net_ads_sid(int argc, const char **argv)
2373 {
2374         ADS_STRUCT *ads;
2375         ADS_STATUS rc;
2376         const char *sid_string;
2377         const char **attrs;
2378         LDAPMessage *res = NULL;
2379         DOM_SID sid;
2380
2381         if (argc < 1) {
2382                 return net_ads_sid_usage(argc, argv);
2383         }
2384
2385         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2386                 return -1;
2387         }
2388
2389         sid_string = argv[0];
2390         attrs = (argv + 1);
2391
2392         if (!string_to_sid(&sid, sid_string)) {
2393                 d_fprintf(stderr, "could not convert sid\n");
2394                 ads_destroy(&ads);
2395                 return -1;
2396         }
2397
2398         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2399         if (!ADS_ERR_OK(rc)) {
2400                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2401                 ads_destroy(&ads);
2402                 return -1;
2403         }
2404
2405         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2406
2407         /* dump the results */
2408         ads_dump(ads, res);
2409
2410         ads_msgfree(ads, res);
2411         ads_destroy(&ads);
2412
2413         return 0;
2414 }
2415
2416
2417 static int net_ads_keytab_usage(int argc, const char **argv)
2418 {
2419         d_printf(
2420                 "net ads keytab <COMMAND>\n"\
2421 "<COMMAND> can be either:\n"\
2422 "  ADD       Adds new service principal\n"\
2423 "  CREATE    Creates a fresh keytab\n"\
2424 "  FLUSH     Flushes out all keytab entries\n"\
2425 "  HELP      Prints this help message\n"\
2426 "  LIST      List the keytab\n"\
2427 "The ADD and LIST command will take arguments, the other commands\n"\
2428 "will not take any arguments.   The arguments given to ADD\n"\
2429 "should be a list of principals to add.  For example, \n"\
2430 "   net ads keytab add srv1 srv2\n"\
2431 "will add principals for the services srv1 and srv2 to the\n"\
2432 "system's keytab.\n"\
2433 "The LIST command takes a keytabname.\n"\
2434 "\n"
2435                 );
2436         return -1;
2437 }
2438
2439 static int net_ads_keytab_flush(int argc, const char **argv)
2440 {
2441         int ret;
2442         ADS_STRUCT *ads;
2443
2444         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2445                 return -1;
2446         }
2447         ret = ads_keytab_flush(ads);
2448         ads_destroy(&ads);
2449         return ret;
2450 }
2451
2452 static int net_ads_keytab_add(int argc, const char **argv)
2453 {
2454         int i;
2455         int ret = 0;
2456         ADS_STRUCT *ads;
2457
2458         d_printf("Processing principals to add...\n");
2459         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2460                 return -1;
2461         }
2462         for (i = 0; i < argc; i++) {
2463                 ret |= ads_keytab_add_entry(ads, argv[i]);
2464         }
2465         ads_destroy(&ads);
2466         return ret;
2467 }
2468
2469 static int net_ads_keytab_create(int argc, const char **argv)
2470 {
2471         ADS_STRUCT *ads;
2472         int ret;
2473
2474         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2475                 return -1;
2476         }
2477         ret = ads_keytab_create_default(ads);
2478         ads_destroy(&ads);
2479         return ret;
2480 }
2481
2482 static int net_ads_keytab_list(int argc, const char **argv)
2483 {
2484         const char *keytab = NULL;
2485
2486         if (argc >= 1) {
2487                 keytab = argv[0];
2488         }
2489
2490         return ads_keytab_list(keytab);
2491 }
2492
2493
2494 int net_ads_keytab(int argc, const char **argv)
2495 {
2496         struct functable func[] = {
2497                 {"ADD", net_ads_keytab_add},
2498                 {"CREATE", net_ads_keytab_create},
2499                 {"FLUSH", net_ads_keytab_flush},
2500                 {"HELP", net_ads_keytab_usage},
2501                 {"LIST", net_ads_keytab_list},
2502                 {NULL, NULL}
2503         };
2504
2505         if (!lp_use_kerberos_keytab()) {
2506                 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2507 use keytab functions.\n");
2508         }
2509
2510         return net_run_function(argc, argv, func, net_ads_keytab_usage);
2511 }
2512
2513 static int net_ads_kerberos_usage(int argc, const char **argv)
2514 {
2515         d_printf(
2516                 "net ads kerberos <COMMAND>\n"\
2517                 "<COMMAND> can be either:\n"\
2518                 "  RENEW     Renew TGT from existing credential cache\n"\
2519                 "  PAC       Dumps the Kerberos PAC\n"\
2520                 "  KINIT     Retrieve Ticket Granting Ticket (TGT)\n"\
2521                 "\n"
2522         );
2523
2524         return -1;
2525 }
2526
2527 static int net_ads_kerberos_renew(int argc, const char **argv)
2528 {
2529         int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2530         if (ret) {
2531                 d_printf("failed to renew kerberos ticket: %s\n",
2532                         error_message(ret));
2533         }
2534         return ret;
2535 }
2536
2537 static int net_ads_kerberos_pac(int argc, const char **argv)
2538 {
2539         PAC_DATA *pac = NULL;
2540         PAC_LOGON_INFO *info = NULL;
2541         TALLOC_CTX *mem_ctx = NULL;
2542         NTSTATUS status;
2543         int ret = -1;
2544
2545         mem_ctx = talloc_init("net_ads_kerberos_pac");
2546         if (!mem_ctx) {
2547                 goto out;
2548         }
2549
2550         opt_password = net_prompt_pass(opt_user_name);
2551
2552         status = kerberos_return_pac(mem_ctx,
2553                                      opt_user_name,
2554                                      opt_password,
2555                                      0,
2556                                      NULL,
2557                                      NULL,
2558                                      NULL,
2559                                      True,
2560                                      True,
2561                                      2592000, /* one month */
2562                                      &pac);
2563         if (!NT_STATUS_IS_OK(status)) {
2564                 d_printf("failed to query kerberos PAC: %s\n",
2565                         nt_errstr(status));
2566                 goto out;
2567         }
2568
2569         info = get_logon_info_from_pac(pac);
2570         if (info) {
2571                 dump_pac_logon_info(0, info);
2572         }
2573
2574         ret = 0;
2575  out:
2576         TALLOC_FREE(mem_ctx);
2577         return ret;
2578 }
2579
2580 static int net_ads_kerberos_kinit(int argc, const char **argv)
2581 {
2582         TALLOC_CTX *mem_ctx = NULL;
2583         int ret = -1;
2584         NTSTATUS status;
2585
2586         mem_ctx = talloc_init("net_ads_kerberos_kinit");
2587         if (!mem_ctx) {
2588                 goto out;
2589         }
2590
2591         opt_password = net_prompt_pass(opt_user_name);
2592
2593         ret = kerberos_kinit_password_ext(opt_user_name,
2594                                           opt_password,
2595                                           0,
2596                                           NULL,
2597                                           NULL,
2598                                           NULL,
2599                                           True,
2600                                           True,
2601                                           2592000, /* one month */
2602                                           &status);
2603         if (ret) {
2604                 d_printf("failed to kinit password: %s\n",
2605                         nt_errstr(status));
2606         }
2607  out:
2608         return ret;
2609 }
2610
2611 int net_ads_kerberos(int argc, const char **argv)
2612 {
2613         struct functable func[] = {
2614                 {"KINIT", net_ads_kerberos_kinit},
2615                 {"RENEW", net_ads_kerberos_renew},
2616                 {"PAC", net_ads_kerberos_pac},
2617                 {"HELP", net_ads_kerberos_usage},
2618                 {NULL, NULL}
2619         };
2620
2621         return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2622 }
2623
2624
2625 int net_ads_help(int argc, const char **argv)
2626 {
2627         struct functable func[] = {
2628                 {"USER", net_ads_user_usage},
2629                 {"GROUP", net_ads_group_usage},
2630                 {"PRINTER", net_ads_printer_usage},
2631                 {"SEARCH", net_ads_search_usage},
2632                 {"INFO", net_ads_info},
2633                 {"JOIN", net_ads_join_usage},
2634                 {"DNS", net_ads_dns_usage},
2635                 {"LEAVE", net_ads_leave},
2636                 {"STATUS", net_ads_status},
2637                 {"PASSWORD", net_ads_password},
2638                 {"CHANGETRUSTPW", net_ads_changetrustpw},
2639                 {NULL, NULL}
2640         };
2641
2642         return net_run_function(argc, argv, func, net_ads_usage);
2643 }
2644
2645 int net_ads(int argc, const char **argv)
2646 {
2647         struct functable func[] = {
2648                 {"INFO", net_ads_info},
2649                 {"JOIN", net_ads_join},
2650                 {"TESTJOIN", net_ads_testjoin},
2651                 {"LEAVE", net_ads_leave},
2652                 {"STATUS", net_ads_status},
2653                 {"USER", net_ads_user},
2654                 {"GROUP", net_ads_group},
2655                 {"DNS", net_ads_dns},
2656                 {"PASSWORD", net_ads_password},
2657                 {"CHANGETRUSTPW", net_ads_changetrustpw},
2658                 {"PRINTER", net_ads_printer},
2659                 {"SEARCH", net_ads_search},
2660                 {"DN", net_ads_dn},
2661                 {"SID", net_ads_sid},
2662                 {"WORKGROUP", net_ads_workgroup},
2663                 {"LOOKUP", net_ads_lookup},
2664                 {"KEYTAB", net_ads_keytab},
2665                 {"GPO", net_ads_gpo},
2666                 {"KERBEROS", net_ads_kerberos},
2667                 {"HELP", net_ads_help},
2668                 {NULL, NULL}
2669         };
2670
2671         return net_run_function(argc, argv, func, net_ads_usage);
2672 }
2673
2674 #else
2675
2676 static int net_ads_noads(void)
2677 {
2678         d_fprintf(stderr, "ADS support not compiled in\n");
2679         return -1;
2680 }
2681
2682 int net_ads_keytab(int argc, const char **argv)
2683 {
2684         return net_ads_noads();
2685 }
2686
2687 int net_ads_kerberos(int argc, const char **argv)
2688 {
2689         return net_ads_noads();
2690 }
2691
2692 int net_ads_usage(int argc, const char **argv)
2693 {
2694         return net_ads_noads();
2695 }
2696
2697 int net_ads_help(int argc, const char **argv)
2698 {
2699         return net_ads_noads();
2700 }
2701
2702 int net_ads_changetrustpw(int argc, const char **argv)
2703 {
2704         return net_ads_noads();
2705 }
2706
2707 int net_ads_join(int argc, const char **argv)
2708 {
2709         return net_ads_noads();
2710 }
2711
2712 int net_ads_user(int argc, const char **argv)
2713 {
2714         return net_ads_noads();
2715 }
2716
2717 int net_ads_group(int argc, const char **argv)
2718 {
2719         return net_ads_noads();
2720 }
2721
2722 /* this one shouldn't display a message */
2723 int net_ads_check(void)
2724 {
2725         return -1;
2726 }
2727
2728 int net_ads_check_our_domain(void)
2729 {
2730         return -1;
2731 }
2732
2733 int net_ads(int argc, const char **argv)
2734 {
2735         return net_ads_usage(argc, argv);
2736 }
2737
2738 #endif  /* WITH_ADS */