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