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