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