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