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