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