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