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