3b671fc600101fb667002cfe8b289959661c6ecb
[obnox/samba/samba-obnox.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(struct net_context *c,
1135                                         TALLOC_CTX *ctx, ADS_STRUCT *ads,
1136                                         const char *machine_name,
1137                                         const struct sockaddr_storage *addrs,
1138                                         int num_addrs)
1139 {
1140         struct dns_rr_ns *nameservers = NULL;
1141         int ns_count = 0, i;
1142         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1143         DNS_ERROR dns_err;
1144         fstring dns_server;
1145         const char *dns_hosts_file;
1146         const char *dnsdomain = NULL;
1147         char *root_domain = NULL;
1148
1149         if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1150                 d_printf(_("No DNS domain configured for %s. "
1151                            "Unable to perform DNS Update.\n"), machine_name);
1152                 status = NT_STATUS_INVALID_PARAMETER;
1153                 goto done;
1154         }
1155         dnsdomain++;
1156
1157         dns_hosts_file = lp_parm_const_string(-1, "resolv", "host file", NULL);
1158         status = ads_dns_lookup_ns(ctx, dns_hosts_file,
1159                                    dnsdomain, &nameservers, &ns_count);
1160         if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1161                 /* Child domains often do not have NS records.  Look
1162                    for the NS record for the forest root domain
1163                    (rootDomainNamingContext in therootDSE) */
1164
1165                 const char *rootname_attrs[] =  { "rootDomainNamingContext", NULL };
1166                 LDAPMessage *msg = NULL;
1167                 char *root_dn;
1168                 ADS_STATUS ads_status;
1169
1170                 if ( !ads->ldap.ld ) {
1171                         ads_status = ads_connect( ads );
1172                         if ( !ADS_ERR_OK(ads_status) ) {
1173                                 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1174                                 goto done;
1175                         }
1176                 }
1177
1178                 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1179                                        "(objectclass=*)", rootname_attrs, &msg);
1180                 if (!ADS_ERR_OK(ads_status)) {
1181                         goto done;
1182                 }
1183
1184                 root_dn = ads_pull_string(ads, ctx, msg,  "rootDomainNamingContext");
1185                 if ( !root_dn ) {
1186                         ads_msgfree( ads, msg );
1187                         goto done;
1188                 }
1189
1190                 root_domain = ads_build_domain( root_dn );
1191
1192                 /* cleanup */
1193                 ads_msgfree( ads, msg );
1194
1195                 /* try again for NS servers */
1196
1197                 status = ads_dns_lookup_ns(ctx, dns_hosts_file, root_domain,
1198                                            &nameservers, &ns_count);
1199
1200                 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1201                         DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1202                          "realm\n", ads->config.realm));
1203                         goto done;
1204                 }
1205
1206                 dnsdomain = root_domain;
1207
1208         }
1209
1210         for (i=0; i < ns_count; i++) {
1211
1212                 status = NT_STATUS_UNSUCCESSFUL;
1213
1214                 /* Now perform the dns update - we'll try non-secure and if we fail,
1215                    we'll follow it up with a secure update */
1216
1217                 fstrcpy( dns_server, nameservers[i].hostname );
1218
1219                 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1220                 if (ERR_DNS_IS_OK(dns_err)) {
1221                         status = NT_STATUS_OK;
1222                         goto done;
1223                 }
1224
1225                 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1226                     ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1227                     ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1228                         DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1229                                 dns_errstr(dns_err)));
1230                         continue;
1231                 }
1232
1233                 d_printf(_("DNS Update for %s failed: %s\n"),
1234                         machine_name, dns_errstr(dns_err));
1235                 status = NT_STATUS_UNSUCCESSFUL;
1236                 goto done;
1237         }
1238
1239 done:
1240
1241         SAFE_FREE( root_domain );
1242
1243         return status;
1244 }
1245
1246 static NTSTATUS net_update_dns_ext(struct net_context *c,
1247                                    TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1248                                    const char *hostname,
1249                                    struct sockaddr_storage *iplist,
1250                                    int num_addrs)
1251 {
1252         struct sockaddr_storage *iplist_alloc = NULL;
1253         fstring machine_name;
1254         NTSTATUS status;
1255
1256         if (hostname) {
1257                 fstrcpy(machine_name, hostname);
1258         } else {
1259                 name_to_fqdn( machine_name, lp_netbios_name() );
1260         }
1261         if (!strlower_m( machine_name )) {
1262                 return NT_STATUS_INVALID_PARAMETER;
1263         }
1264
1265         if (num_addrs == 0 || iplist == NULL) {
1266                 /*
1267                  * Get our ip address
1268                  * (not the 127.0.0.x address but a real ip address)
1269                  */
1270                 num_addrs = get_my_ip_address(&iplist_alloc);
1271                 if ( num_addrs <= 0 ) {
1272                         DEBUG(4, ("net_update_dns_ext: Failed to find my "
1273                                   "non-loopback IP addresses!\n"));
1274                         return NT_STATUS_INVALID_PARAMETER;
1275                 }
1276                 iplist = iplist_alloc;
1277         }
1278
1279         status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1280                                          iplist, num_addrs);
1281
1282         SAFE_FREE(iplist_alloc);
1283         return status;
1284 }
1285
1286 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1287 {
1288         NTSTATUS status;
1289
1290         status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0);
1291         return status;
1292 }
1293 #endif
1294
1295
1296 /*******************************************************************
1297  ********************************************************************/
1298
1299 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1300 {
1301         d_printf(_("net ads join [options]\n"
1302                    "Valid options:\n"));
1303         d_printf(_("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n"
1304                    "                      The deault UPN is in the form host/netbiosname@REALM.\n"));
1305         d_printf(_("   createcomputer=OU  Precreate the computer account in a specific OU.\n"
1306                    "                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1307                    "                      E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1308                    "                      NB: A backslash '\\' is used as escape at multiple levels and may\n"
1309                    "                          need to be doubled or even quadrupled.  It is not used as a separator.\n"));
1310         d_printf(_("   osName=string      Set the operatingSystem attribute during the join.\n"));
1311         d_printf(_("   osVer=string       Set the operatingSystemVersion attribute during the join.\n"
1312                    "                      NB: osName and osVer must be specified together for either to take effect.\n"
1313                    "                          Also, the operatingSystemService attribute is also set when along with\n"
1314                    "                          the two other attributes.\n"));
1315
1316         return -1;
1317 }
1318
1319
1320 static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1321 {
1322 #if defined(WITH_DNS_UPDATES)
1323         ADS_STRUCT *ads_dns = NULL;
1324         int ret;
1325         NTSTATUS status;
1326
1327         /*
1328          * In a clustered environment, don't do dynamic dns updates:
1329          * Registering the set of ip addresses that are assigned to
1330          * the interfaces of the node that performs the join does usually
1331          * not have the desired effect, since the local interfaces do not
1332          * carry the complete set of the cluster's public IP addresses.
1333          * And it can also contain internal addresses that should not
1334          * be visible to the outside at all.
1335          * In order to do dns updates in a clustererd setup, use
1336          * net ads dns register.
1337          */
1338         if (lp_clustering()) {
1339                 d_fprintf(stderr, _("Not doing automatic DNS update in a "
1340                                     "clustered setup.\n"));
1341                 return;
1342         }
1343
1344         if (!r->out.domain_is_ad) {
1345                 return;
1346         }
1347
1348         /*
1349          * We enter this block with user creds.
1350          * kinit with the machine password to do dns update.
1351          */
1352
1353         ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
1354
1355         if (ads_dns == NULL) {
1356                 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1357                 goto done;
1358         }
1359
1360         use_in_memory_ccache();
1361
1362         ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1363         if (ret == -1) {
1364                 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1365                 goto done;
1366         }
1367
1368         ads_dns->auth.password = secrets_fetch_machine_password(
1369                 r->out.netbios_domain_name, NULL, NULL);
1370         if (ads_dns->auth.password == NULL) {
1371                 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1372                 goto done;
1373         }
1374
1375         ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1376         if (ads_dns->auth.realm == NULL) {
1377                 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1378                 goto done;
1379         }
1380
1381         if (!strupper_m(ads_dns->auth.realm)) {
1382                 d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
1383                 goto done;
1384         }
1385
1386         ret = ads_kinit_password(ads_dns);
1387         if (ret != 0) {
1388                 d_fprintf(stderr,
1389                           _("DNS update failed: kinit failed: %s\n"),
1390                           error_message(ret));
1391                 goto done;
1392         }
1393
1394         status = net_update_dns(c, ctx, ads_dns, NULL);
1395         if (!NT_STATUS_IS_OK(status)) {
1396                 d_fprintf( stderr, _("DNS update failed: %s\n"),
1397                           nt_errstr(status));
1398         }
1399
1400 done:
1401         ads_destroy(&ads_dns);
1402 #endif
1403
1404         return;
1405 }
1406
1407
1408 int net_ads_join(struct net_context *c, int argc, const char **argv)
1409 {
1410         TALLOC_CTX *ctx = NULL;
1411         struct libnet_JoinCtx *r = NULL;
1412         const char *domain = lp_realm();
1413         WERROR werr = WERR_SETUP_NOT_JOINED;
1414         bool createupn = false;
1415         const char *machineupn = NULL;
1416         const char *create_in_ou = NULL;
1417         int i;
1418         const char *os_name = NULL;
1419         const char *os_version = NULL;
1420         bool modify_config = lp_config_backend_is_registry();
1421
1422         if (c->display_usage)
1423                 return net_ads_join_usage(c, argc, argv);
1424
1425         if (!modify_config) {
1426
1427                 werr = check_ads_config();
1428                 if (!W_ERROR_IS_OK(werr)) {
1429                         d_fprintf(stderr, _("Invalid configuration.  Exiting....\n"));
1430                         goto fail;
1431                 }
1432         }
1433
1434         if (!(ctx = talloc_init("net_ads_join"))) {
1435                 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1436                 werr = WERR_NOMEM;
1437                 goto fail;
1438         }
1439
1440         if (!c->opt_kerberos) {
1441                 use_in_memory_ccache();
1442         }
1443
1444         werr = libnet_init_JoinCtx(ctx, &r);
1445         if (!W_ERROR_IS_OK(werr)) {
1446                 goto fail;
1447         }
1448
1449         /* process additional command line args */
1450
1451         for ( i=0; i<argc; i++ ) {
1452                 if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1453                         createupn = true;
1454                         machineupn = get_string_param(argv[i]);
1455                 }
1456                 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1457                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1458                                 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1459                                 werr = WERR_INVALID_PARAM;
1460                                 goto fail;
1461                         }
1462                 }
1463                 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1464                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1465                                 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1466                                 werr = WERR_INVALID_PARAM;
1467                                 goto fail;
1468                         }
1469                 }
1470                 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1471                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1472                                 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1473                                 werr = WERR_INVALID_PARAM;
1474                                 goto fail;
1475                         }
1476                 }
1477                 else {
1478                         domain = argv[i];
1479                 }
1480         }
1481
1482         if (!*domain) {
1483                 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1484                 werr = WERR_INVALID_PARAM;
1485                 goto fail;
1486         }
1487
1488         if (!c->msg_ctx) {
1489                 d_fprintf(stderr, _("Could not initialise message context. "
1490                         "Try running as root\n"));
1491                 werr = WERR_ACCESS_DENIED;
1492                 goto fail;
1493         }
1494
1495         /* Do the domain join here */
1496
1497         r->in.domain_name       = domain;
1498         r->in.create_upn        = createupn;
1499         r->in.upn               = machineupn;
1500         r->in.account_ou        = create_in_ou;
1501         r->in.os_name           = os_name;
1502         r->in.os_version        = os_version;
1503         r->in.dc_name           = c->opt_host;
1504         r->in.admin_account     = c->opt_user_name;
1505         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1506         r->in.debug             = true;
1507         r->in.use_kerberos      = c->opt_kerberos;
1508         r->in.modify_config     = modify_config;
1509         r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1510                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1511                                   WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1512         r->in.msg_ctx           = c->msg_ctx;
1513
1514         werr = libnet_Join(ctx, r);
1515         if (W_ERROR_EQUAL(werr, WERR_DCNOTFOUND) &&
1516             strequal(domain, lp_realm())) {
1517                 r->in.domain_name = lp_workgroup();
1518                 werr = libnet_Join(ctx, r);
1519         }
1520         if (!W_ERROR_IS_OK(werr)) {
1521                 goto fail;
1522         }
1523
1524         /* Check the short name of the domain */
1525
1526         if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1527                 d_printf(_("The workgroup in %s does not match the short\n"
1528                            "domain name obtained from the server.\n"
1529                            "Using the name [%s] from the server.\n"
1530                            "You should set \"workgroup = %s\" in %s.\n"),
1531                          get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1532                          r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1533         }
1534
1535         d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1536
1537         if (r->out.dns_domain_name) {
1538                 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1539                         r->out.dns_domain_name);
1540         } else {
1541                 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1542                         r->out.netbios_domain_name);
1543         }
1544
1545         /*
1546          * We try doing the dns update (if it was compiled in).
1547          * If the dns update fails, we still consider the join
1548          * operation as succeeded if we came this far.
1549          */
1550         _net_ads_join_dns_updates(c, ctx, r);
1551
1552         TALLOC_FREE(r);
1553         TALLOC_FREE( ctx );
1554
1555         return 0;
1556
1557 fail:
1558         /* issue an overall failure message at the end. */
1559         d_printf(_("Failed to join domain: %s\n"),
1560                 r && r->out.error_string ? r->out.error_string :
1561                 get_friendly_werror_msg(werr));
1562         TALLOC_FREE( ctx );
1563
1564         return -1;
1565 }
1566
1567 /*******************************************************************
1568  ********************************************************************/
1569
1570 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1571 {
1572 #if defined(WITH_DNS_UPDATES)
1573         ADS_STRUCT *ads;
1574         ADS_STATUS status;
1575         NTSTATUS ntstatus;
1576         TALLOC_CTX *ctx;
1577         const char *hostname = NULL;
1578         const char **addrs_list = NULL;
1579         struct sockaddr_storage *addrs = NULL;
1580         int num_addrs = 0;
1581         int count;
1582
1583 #ifdef DEVELOPER
1584         talloc_enable_leak_report();
1585 #endif
1586
1587         if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1588                 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1589                                     "detection of addresses in a clustered "
1590                                     "setup.\n"));
1591                 c->display_usage = true;
1592         }
1593
1594         if (c->display_usage) {
1595                 d_printf(  "%s\n"
1596                            "net ads dns register [hostname [IP [IP...]]]\n"
1597                            "    %s\n",
1598                          _("Usage:"),
1599                          _("Register hostname with DNS\n"));
1600                 return -1;
1601         }
1602
1603         if (!(ctx = talloc_init("net_ads_dns"))) {
1604                 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1605                 return -1;
1606         }
1607
1608         if (argc >= 1) {
1609                 hostname = argv[0];
1610         }
1611
1612         if (argc > 1) {
1613                 num_addrs = argc - 1;
1614                 addrs_list = &argv[1];
1615         } else if (lp_clustering()) {
1616                 addrs_list = lp_cluster_addresses();
1617                 num_addrs = str_list_length(addrs_list);
1618         }
1619
1620         if (num_addrs > 0) {
1621                 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1622                 if (addrs == NULL) {
1623                         d_fprintf(stderr, _("Error allocating memory!\n"));
1624                         talloc_free(ctx);
1625                         return -1;
1626                 }
1627         }
1628
1629         for (count = 0; count < num_addrs; count++) {
1630                 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1631                         d_fprintf(stderr, "%s '%s'.\n",
1632                                           _("Cannot interpret address"),
1633                                           addrs_list[count]);
1634                         talloc_free(ctx);
1635                         return -1;
1636                 }
1637         }
1638
1639         status = ads_startup(c, true, &ads);
1640         if ( !ADS_ERR_OK(status) ) {
1641                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1642                 TALLOC_FREE(ctx);
1643                 return -1;
1644         }
1645
1646         ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs);
1647         if (!NT_STATUS_IS_OK(ntstatus)) {
1648                 d_fprintf( stderr, _("DNS update failed!\n") );
1649                 ads_destroy( &ads );
1650                 TALLOC_FREE( ctx );
1651                 return -1;
1652         }
1653
1654         d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1655
1656         ads_destroy(&ads);
1657         TALLOC_FREE( ctx );
1658
1659         return 0;
1660 #else
1661         d_fprintf(stderr,
1662                   _("DNS update support not enabled at compile time!\n"));
1663         return -1;
1664 #endif
1665 }
1666
1667 #if defined(WITH_DNS_UPDATES)
1668 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1669 #endif
1670
1671 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1672 {
1673 #if defined(WITH_DNS_UPDATES)
1674         DNS_ERROR err;
1675
1676 #ifdef DEVELOPER
1677         talloc_enable_leak_report();
1678 #endif
1679
1680         if (argc != 2 || c->display_usage) {
1681                 d_printf(  "%s\n"
1682                            "    %s\n"
1683                            "    %s\n",
1684                          _("Usage:"),
1685                          _("net ads dns gethostbyname <server> <name>\n"),
1686                          _("  Look up hostname from the AD\n"
1687                            "    server\tName server to use\n"
1688                            "    name\tName to look up\n"));
1689                 return -1;
1690         }
1691
1692         err = do_gethostbyname(argv[0], argv[1]);
1693
1694         d_printf(_("do_gethostbyname returned %s (%d)\n"),
1695                 dns_errstr(err), ERROR_DNS_V(err));
1696 #endif
1697         return 0;
1698 }
1699
1700 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1701 {
1702         struct functable func[] = {
1703                 {
1704                         "register",
1705                         net_ads_dns_register,
1706                         NET_TRANSPORT_ADS,
1707                         N_("Add host dns entry to AD"),
1708                         N_("net ads dns register\n"
1709                            "    Add host dns entry to AD")
1710                 },
1711                 {
1712                         "gethostbyname",
1713                         net_ads_dns_gethostbyname,
1714                         NET_TRANSPORT_ADS,
1715                         N_("Look up host"),
1716                         N_("net ads dns gethostbyname\n"
1717                            "    Look up host")
1718                 },
1719                 {NULL, NULL, 0, NULL, NULL}
1720         };
1721
1722         return net_run_function(c, argc, argv, "net ads dns", func);
1723 }
1724
1725 /*******************************************************************
1726  ********************************************************************/
1727
1728 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1729 {
1730         d_printf(_(
1731 "\nnet ads printer search <printer>"
1732 "\n\tsearch for a printer in the directory\n"
1733 "\nnet ads printer info <printer> <server>"
1734 "\n\tlookup info in directory for printer on server"
1735 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1736 "\nnet ads printer publish <printername>"
1737 "\n\tpublish printer in directory"
1738 "\n\t(note: printer name is required)\n"
1739 "\nnet ads printer remove <printername>"
1740 "\n\tremove printer from directory"
1741 "\n\t(note: printer name is required)\n"));
1742         return -1;
1743 }
1744
1745 /*******************************************************************
1746  ********************************************************************/
1747
1748 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1749 {
1750         ADS_STRUCT *ads;
1751         ADS_STATUS rc;
1752         LDAPMessage *res = NULL;
1753
1754         if (c->display_usage) {
1755                 d_printf(  "%s\n"
1756                            "net ads printer search\n"
1757                            "    %s\n",
1758                          _("Usage:"),
1759                          _("List printers in the AD"));
1760                 return 0;
1761         }
1762
1763         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1764                 return -1;
1765         }
1766
1767         rc = ads_find_printers(ads, &res);
1768
1769         if (!ADS_ERR_OK(rc)) {
1770                 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1771                 ads_msgfree(ads, res);
1772                 ads_destroy(&ads);
1773                 return -1;
1774         }
1775
1776         if (ads_count_replies(ads, res) == 0) {
1777                 d_fprintf(stderr, _("No results found\n"));
1778                 ads_msgfree(ads, res);
1779                 ads_destroy(&ads);
1780                 return -1;
1781         }
1782
1783         ads_dump(ads, res);
1784         ads_msgfree(ads, res);
1785         ads_destroy(&ads);
1786         return 0;
1787 }
1788
1789 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1790 {
1791         ADS_STRUCT *ads;
1792         ADS_STATUS rc;
1793         const char *servername, *printername;
1794         LDAPMessage *res = NULL;
1795
1796         if (c->display_usage) {
1797                 d_printf("%s\n%s",
1798                          _("Usage:"),
1799                          _("net ads printer info [printername [servername]]\n"
1800                            "  Display printer info from AD\n"
1801                            "    printername\tPrinter name or wildcard\n"
1802                            "    servername\tName of the print server\n"));
1803                 return 0;
1804         }
1805
1806         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1807                 return -1;
1808         }
1809
1810         if (argc > 0) {
1811                 printername = argv[0];
1812         } else {
1813                 printername = "*";
1814         }
1815
1816         if (argc > 1) {
1817                 servername =  argv[1];
1818         } else {
1819                 servername = lp_netbios_name();
1820         }
1821
1822         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1823
1824         if (!ADS_ERR_OK(rc)) {
1825                 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1826                         servername, ads_errstr(rc));
1827                 ads_msgfree(ads, res);
1828                 ads_destroy(&ads);
1829                 return -1;
1830         }
1831
1832         if (ads_count_replies(ads, res) == 0) {
1833                 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1834                 ads_msgfree(ads, res);
1835                 ads_destroy(&ads);
1836                 return -1;
1837         }
1838
1839         ads_dump(ads, res);
1840         ads_msgfree(ads, res);
1841         ads_destroy(&ads);
1842
1843         return 0;
1844 }
1845
1846 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1847 {
1848         ADS_STRUCT *ads;
1849         ADS_STATUS rc;
1850         const char *servername, *printername;
1851         struct cli_state *cli = NULL;
1852         struct rpc_pipe_client *pipe_hnd = NULL;
1853         struct sockaddr_storage server_ss;
1854         NTSTATUS nt_status;
1855         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1856         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1857         char *prt_dn, *srv_dn, **srv_cn;
1858         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1859         LDAPMessage *res = NULL;
1860
1861         if (argc < 1 || c->display_usage) {
1862                 d_printf("%s\n%s",
1863                          _("Usage:"),
1864                          _("net ads printer publish <printername> [servername]\n"
1865                            "  Publish printer in AD\n"
1866                            "    printername\tName of the printer\n"
1867                            "    servername\tName of the print server\n"));
1868                 talloc_destroy(mem_ctx);
1869                 return -1;
1870         }
1871
1872         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1873                 talloc_destroy(mem_ctx);
1874                 return -1;
1875         }
1876
1877         printername = argv[0];
1878
1879         if (argc == 2) {
1880                 servername = argv[1];
1881         } else {
1882                 servername = lp_netbios_name();
1883         }
1884
1885         /* Get printer data from SPOOLSS */
1886
1887         resolve_name(servername, &server_ss, 0x20, false);
1888
1889         nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
1890                                         &server_ss, 0,
1891                                         "IPC$", "IPC",
1892                                         c->opt_user_name, c->opt_workgroup,
1893                                         c->opt_password ? c->opt_password : "",
1894                                         CLI_FULL_CONNECTION_USE_KERBEROS,
1895                                         SMB_SIGNING_DEFAULT);
1896
1897         if (NT_STATUS_IS_ERR(nt_status)) {
1898                 d_fprintf(stderr, _("Unable to open a connection to %s to "
1899                                     "obtain data for %s\n"),
1900                           servername, printername);
1901                 ads_destroy(&ads);
1902                 talloc_destroy(mem_ctx);
1903                 return -1;
1904         }
1905
1906         /* Publish on AD server */
1907
1908         ads_find_machine_acct(ads, &res, servername);
1909
1910         if (ads_count_replies(ads, res) == 0) {
1911                 d_fprintf(stderr, _("Could not find machine account for server "
1912                                     "%s\n"),
1913                          servername);
1914                 ads_destroy(&ads);
1915                 talloc_destroy(mem_ctx);
1916                 return -1;
1917         }
1918
1919         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1920         srv_cn = ldap_explode_dn(srv_dn, 1);
1921
1922         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1923         printername_escaped = escape_rdn_val_string_alloc(printername);
1924         if (!srv_cn_escaped || !printername_escaped) {
1925                 SAFE_FREE(srv_cn_escaped);
1926                 SAFE_FREE(printername_escaped);
1927                 d_fprintf(stderr, _("Internal error, out of memory!"));
1928                 ads_destroy(&ads);
1929                 talloc_destroy(mem_ctx);
1930                 return -1;
1931         }
1932
1933         if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1934                 SAFE_FREE(srv_cn_escaped);
1935                 SAFE_FREE(printername_escaped);
1936                 d_fprintf(stderr, _("Internal error, out of memory!"));
1937                 ads_destroy(&ads);
1938                 talloc_destroy(mem_ctx);
1939                 return -1;
1940         }
1941
1942         SAFE_FREE(srv_cn_escaped);
1943         SAFE_FREE(printername_escaped);
1944
1945         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1946         if (!NT_STATUS_IS_OK(nt_status)) {
1947                 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
1948                          servername);
1949                 SAFE_FREE(prt_dn);
1950                 ads_destroy(&ads);
1951                 talloc_destroy(mem_ctx);
1952                 return -1;
1953         }
1954
1955         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1956                                                               printername))) {
1957                 SAFE_FREE(prt_dn);
1958                 ads_destroy(&ads);
1959                 talloc_destroy(mem_ctx);
1960                 return -1;
1961         }
1962
1963         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1964         if (!ADS_ERR_OK(rc)) {
1965                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1966                 SAFE_FREE(prt_dn);
1967                 ads_destroy(&ads);
1968                 talloc_destroy(mem_ctx);
1969                 return -1;
1970         }
1971
1972         d_printf("published printer\n");
1973         SAFE_FREE(prt_dn);
1974         ads_destroy(&ads);
1975         talloc_destroy(mem_ctx);
1976
1977         return 0;
1978 }
1979
1980 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1981 {
1982         ADS_STRUCT *ads;
1983         ADS_STATUS rc;
1984         const char *servername;
1985         char *prt_dn;
1986         LDAPMessage *res = NULL;
1987
1988         if (argc < 1 || c->display_usage) {
1989                 d_printf("%s\n%s",
1990                          _("Usage:"),
1991                          _("net ads printer remove <printername> [servername]\n"
1992                            "  Remove a printer from the AD\n"
1993                            "    printername\tName of the printer\n"
1994                            "    servername\tName of the print server\n"));
1995                 return -1;
1996         }
1997
1998         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1999                 return -1;
2000         }
2001
2002         if (argc > 1) {
2003                 servername = argv[1];
2004         } else {
2005                 servername = lp_netbios_name();
2006         }
2007
2008         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2009
2010         if (!ADS_ERR_OK(rc)) {
2011                 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2012                 ads_msgfree(ads, res);
2013                 ads_destroy(&ads);
2014                 return -1;
2015         }
2016
2017         if (ads_count_replies(ads, res) == 0) {
2018                 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2019                 ads_msgfree(ads, res);
2020                 ads_destroy(&ads);
2021                 return -1;
2022         }
2023
2024         prt_dn = ads_get_dn(ads, talloc_tos(), res);
2025         ads_msgfree(ads, res);
2026         rc = ads_del_dn(ads, prt_dn);
2027         TALLOC_FREE(prt_dn);
2028
2029         if (!ADS_ERR_OK(rc)) {
2030                 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2031                 ads_destroy(&ads);
2032                 return -1;
2033         }
2034
2035         ads_destroy(&ads);
2036         return 0;
2037 }
2038
2039 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2040 {
2041         struct functable func[] = {
2042                 {
2043                         "search",
2044                         net_ads_printer_search,
2045                         NET_TRANSPORT_ADS,
2046                         N_("Search for a printer"),
2047                         N_("net ads printer search\n"
2048                            "    Search for a printer")
2049                 },
2050                 {
2051                         "info",
2052                         net_ads_printer_info,
2053                         NET_TRANSPORT_ADS,
2054                         N_("Display printer information"),
2055                         N_("net ads printer info\n"
2056                            "    Display printer information")
2057                 },
2058                 {
2059                         "publish",
2060                         net_ads_printer_publish,
2061                         NET_TRANSPORT_ADS,
2062                         N_("Publish a printer"),
2063                         N_("net ads printer publish\n"
2064                            "    Publish a printer")
2065                 },
2066                 {
2067                         "remove",
2068                         net_ads_printer_remove,
2069                         NET_TRANSPORT_ADS,
2070                         N_("Delete a printer"),
2071                         N_("net ads printer remove\n"
2072                            "    Delete a printer")
2073                 },
2074                 {NULL, NULL, 0, NULL, NULL}
2075         };
2076
2077         return net_run_function(c, argc, argv, "net ads printer", func);
2078 }
2079
2080
2081 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2082 {
2083         ADS_STRUCT *ads;
2084         const char *auth_principal = c->opt_user_name;
2085         const char *auth_password = c->opt_password;
2086         const char *realm = NULL;
2087         const char *new_password = NULL;
2088         char *chr, *prompt;
2089         const char *user;
2090         ADS_STATUS ret;
2091
2092         if (c->display_usage) {
2093                 d_printf("%s\n%s",
2094                          _("Usage:"),
2095                          _("net ads password <username>\n"
2096                            "  Change password for user\n"
2097                            "    username\tName of user to change password for\n"));
2098                 return 0;
2099         }
2100
2101         if (c->opt_user_name == NULL || c->opt_password == NULL) {
2102                 d_fprintf(stderr, _("You must supply an administrator "
2103                                     "username/password\n"));
2104                 return -1;
2105         }
2106
2107         if (argc < 1) {
2108                 d_fprintf(stderr, _("ERROR: You must say which username to "
2109                                     "change password for\n"));
2110                 return -1;
2111         }
2112
2113         user = argv[0];
2114         if (!strchr_m(user, '@')) {
2115                 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2116                         return -1;
2117                 }
2118                 user = chr;
2119         }
2120
2121         use_in_memory_ccache();
2122         chr = strchr_m(auth_principal, '@');
2123         if (chr) {
2124                 realm = ++chr;
2125         } else {
2126                 realm = lp_realm();
2127         }
2128
2129         /* use the realm so we can eventually change passwords for users
2130         in realms other than default */
2131         if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2132                 return -1;
2133         }
2134
2135         /* we don't actually need a full connect, but it's the easy way to
2136                 fill in the KDC's addresss */
2137         ads_connect(ads);
2138
2139         if (!ads->config.realm) {
2140                 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2141                 ads_destroy(&ads);
2142                 return -1;
2143         }
2144
2145         if (argv[1]) {
2146                 new_password = (const char *)argv[1];
2147         } else {
2148                 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2149                         return -1;
2150                 }
2151                 new_password = getpass(prompt);
2152                 free(prompt);
2153         }
2154
2155         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2156                                 auth_password, user, new_password, ads->auth.time_offset);
2157         if (!ADS_ERR_OK(ret)) {
2158                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2159                 ads_destroy(&ads);
2160                 return -1;
2161         }
2162
2163         d_printf(_("Password change for %s completed.\n"), user);
2164         ads_destroy(&ads);
2165
2166         return 0;
2167 }
2168
2169 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2170 {
2171         ADS_STRUCT *ads;
2172         char *host_principal;
2173         fstring my_name;
2174         ADS_STATUS ret;
2175
2176         if (c->display_usage) {
2177                 d_printf(  "%s\n"
2178                            "net ads changetrustpw\n"
2179                            "    %s\n",
2180                          _("Usage:"),
2181                          _("Change the machine account's trust password"));
2182                 return 0;
2183         }
2184
2185         if (!secrets_init()) {
2186                 DEBUG(1,("Failed to initialise secrets database\n"));
2187                 return -1;
2188         }
2189
2190         net_use_krb_machine_account(c);
2191
2192         use_in_memory_ccache();
2193
2194         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2195                 return -1;
2196         }
2197
2198         fstrcpy(my_name, lp_netbios_name());
2199         if (!strlower_m(my_name)) {
2200                 ads_destroy(&ads);
2201                 return -1;
2202         }
2203
2204         if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2205                 ads_destroy(&ads);
2206                 return -1;
2207         }
2208         d_printf(_("Changing password for principal: %s\n"), host_principal);
2209
2210         ret = ads_change_trust_account_password(ads, host_principal);
2211
2212         if (!ADS_ERR_OK(ret)) {
2213                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2214                 ads_destroy(&ads);
2215                 SAFE_FREE(host_principal);
2216                 return -1;
2217         }
2218
2219         d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2220
2221         if (USE_SYSTEM_KEYTAB) {
2222                 d_printf(_("Attempting to update system keytab with new password.\n"));
2223                 if (ads_keytab_create_default(ads)) {
2224                         d_printf(_("Failed to update system keytab.\n"));
2225                 }
2226         }
2227
2228         ads_destroy(&ads);
2229         SAFE_FREE(host_principal);
2230
2231         return 0;
2232 }
2233
2234 /*
2235   help for net ads search
2236 */
2237 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2238 {
2239         d_printf(_(
2240                 "\nnet ads search <expression> <attributes...>\n"
2241                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2242                 "The expression is a standard LDAP search expression, and the\n"
2243                 "attributes are a list of LDAP fields to show in the results.\n\n"
2244                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2245                 ));
2246         net_common_flags_usage(c, argc, argv);
2247         return -1;
2248 }
2249
2250
2251 /*
2252   general ADS search function. Useful in diagnosing problems in ADS
2253 */
2254 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2255 {
2256         ADS_STRUCT *ads;
2257         ADS_STATUS rc;
2258         const char *ldap_exp;
2259         const char **attrs;
2260         LDAPMessage *res = NULL;
2261
2262         if (argc < 1 || c->display_usage) {
2263                 return net_ads_search_usage(c, argc, argv);
2264         }
2265
2266         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2267                 return -1;
2268         }
2269
2270         ldap_exp = argv[0];
2271         attrs = (argv + 1);
2272
2273         rc = ads_do_search_retry(ads, ads->config.bind_path,
2274                                LDAP_SCOPE_SUBTREE,
2275                                ldap_exp, attrs, &res);
2276         if (!ADS_ERR_OK(rc)) {
2277                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2278                 ads_destroy(&ads);
2279                 return -1;
2280         }
2281
2282         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2283
2284         /* dump the results */
2285         ads_dump(ads, res);
2286
2287         ads_msgfree(ads, res);
2288         ads_destroy(&ads);
2289
2290         return 0;
2291 }
2292
2293
2294 /*
2295   help for net ads search
2296 */
2297 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2298 {
2299         d_printf(_(
2300                 "\nnet ads dn <dn> <attributes...>\n"
2301                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2302                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2303                 "to show in the results\n\n"
2304                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2305                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2306                 ));
2307         net_common_flags_usage(c, argc, argv);
2308         return -1;
2309 }
2310
2311
2312 /*
2313   general ADS search function. Useful in diagnosing problems in ADS
2314 */
2315 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2316 {
2317         ADS_STRUCT *ads;
2318         ADS_STATUS rc;
2319         const char *dn;
2320         const char **attrs;
2321         LDAPMessage *res = NULL;
2322
2323         if (argc < 1 || c->display_usage) {
2324                 return net_ads_dn_usage(c, argc, argv);
2325         }
2326
2327         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2328                 return -1;
2329         }
2330
2331         dn = argv[0];
2332         attrs = (argv + 1);
2333
2334         rc = ads_do_search_all(ads, dn,
2335                                LDAP_SCOPE_BASE,
2336                                "(objectclass=*)", attrs, &res);
2337         if (!ADS_ERR_OK(rc)) {
2338                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2339                 ads_destroy(&ads);
2340                 return -1;
2341         }
2342
2343         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2344
2345         /* dump the results */
2346         ads_dump(ads, res);
2347
2348         ads_msgfree(ads, res);
2349         ads_destroy(&ads);
2350
2351         return 0;
2352 }
2353
2354 /*
2355   help for net ads sid search
2356 */
2357 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2358 {
2359         d_printf(_(
2360                 "\nnet ads sid <sid> <attributes...>\n"
2361                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2362                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2363                 "to show in the results\n\n"
2364                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2365                 ));
2366         net_common_flags_usage(c, argc, argv);
2367         return -1;
2368 }
2369
2370
2371 /*
2372   general ADS search function. Useful in diagnosing problems in ADS
2373 */
2374 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2375 {
2376         ADS_STRUCT *ads;
2377         ADS_STATUS rc;
2378         const char *sid_string;
2379         const char **attrs;
2380         LDAPMessage *res = NULL;
2381         struct dom_sid sid;
2382
2383         if (argc < 1 || c->display_usage) {
2384                 return net_ads_sid_usage(c, argc, argv);
2385         }
2386
2387         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2388                 return -1;
2389         }
2390
2391         sid_string = argv[0];
2392         attrs = (argv + 1);
2393
2394         if (!string_to_sid(&sid, sid_string)) {
2395                 d_fprintf(stderr, _("could not convert sid\n"));
2396                 ads_destroy(&ads);
2397                 return -1;
2398         }
2399
2400         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2401         if (!ADS_ERR_OK(rc)) {
2402                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2403                 ads_destroy(&ads);
2404                 return -1;
2405         }
2406
2407         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2408
2409         /* dump the results */
2410         ads_dump(ads, res);
2411
2412         ads_msgfree(ads, res);
2413         ads_destroy(&ads);
2414
2415         return 0;
2416 }
2417
2418 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2419 {
2420         int ret;
2421         ADS_STRUCT *ads;
2422
2423         if (c->display_usage) {
2424                 d_printf(  "%s\n"
2425                            "net ads keytab flush\n"
2426                            "    %s\n",
2427                          _("Usage:"),
2428                          _("Delete the whole keytab"));
2429                 return 0;
2430         }
2431
2432         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2433                 return -1;
2434         }
2435         ret = ads_keytab_flush(ads);
2436         ads_destroy(&ads);
2437         return ret;
2438 }
2439
2440 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2441 {
2442         int i;
2443         int ret = 0;
2444         ADS_STRUCT *ads;
2445
2446         if (c->display_usage) {
2447                 d_printf("%s\n%s",
2448                          _("Usage:"),
2449                          _("net ads keytab add <principal> [principal ...]\n"
2450                            "  Add principals to local keytab\n"
2451                            "    principal\tKerberos principal to add to "
2452                            "keytab\n"));
2453                 return 0;
2454         }
2455
2456         d_printf(_("Processing principals to add...\n"));
2457         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2458                 return -1;
2459         }
2460         for (i = 0; i < argc; i++) {
2461                 ret |= ads_keytab_add_entry(ads, argv[i]);
2462         }
2463         ads_destroy(&ads);
2464         return ret;
2465 }
2466
2467 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2468 {
2469         ADS_STRUCT *ads;
2470         int ret;
2471
2472         if (c->display_usage) {
2473                 d_printf(  "%s\n"
2474                            "net ads keytab create\n"
2475                            "    %s\n",
2476                          _("Usage:"),
2477                          _("Create new default keytab"));
2478                 return 0;
2479         }
2480
2481         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2482                 return -1;
2483         }
2484         ret = ads_keytab_create_default(ads);
2485         ads_destroy(&ads);
2486         return ret;
2487 }
2488
2489 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2490 {
2491         const char *keytab = NULL;
2492
2493         if (c->display_usage) {
2494                 d_printf("%s\n%s",
2495                          _("Usage:"),
2496                          _("net ads keytab list [keytab]\n"
2497                            "  List a local keytab\n"
2498                            "    keytab\tKeytab to list\n"));
2499                 return 0;
2500         }
2501
2502         if (argc >= 1) {
2503                 keytab = argv[0];
2504         }
2505
2506         return ads_keytab_list(keytab);
2507 }
2508
2509
2510 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2511 {
2512         struct functable func[] = {
2513                 {
2514                         "add",
2515                         net_ads_keytab_add,
2516                         NET_TRANSPORT_ADS,
2517                         N_("Add a service principal"),
2518                         N_("net ads keytab add\n"
2519                            "    Add a service principal")
2520                 },
2521                 {
2522                         "create",
2523                         net_ads_keytab_create,
2524                         NET_TRANSPORT_ADS,
2525                         N_("Create a fresh keytab"),
2526                         N_("net ads keytab create\n"
2527                            "    Create a fresh keytab")
2528                 },
2529                 {
2530                         "flush",
2531                         net_ads_keytab_flush,
2532                         NET_TRANSPORT_ADS,
2533                         N_("Remove all keytab entries"),
2534                         N_("net ads keytab flush\n"
2535                            "    Remove all keytab entries")
2536                 },
2537                 {
2538                         "list",
2539                         net_ads_keytab_list,
2540                         NET_TRANSPORT_ADS,
2541                         N_("List a keytab"),
2542                         N_("net ads keytab list\n"
2543                            "    List a keytab")
2544                 },
2545                 {NULL, NULL, 0, NULL, NULL}
2546         };
2547
2548         if (!USE_KERBEROS_KEYTAB) {
2549                 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2550                     "keytab method to use keytab functions.\n"));
2551         }
2552
2553         return net_run_function(c, argc, argv, "net ads keytab", func);
2554 }
2555
2556 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2557 {
2558         int ret = -1;
2559
2560         if (c->display_usage) {
2561                 d_printf(  "%s\n"
2562                            "net ads kerberos renew\n"
2563                            "    %s\n",
2564                          _("Usage:"),
2565                          _("Renew TGT from existing credential cache"));
2566                 return 0;
2567         }
2568
2569         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2570         if (ret) {
2571                 d_printf(_("failed to renew kerberos ticket: %s\n"),
2572                         error_message(ret));
2573         }
2574         return ret;
2575 }
2576
2577 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2578 {
2579         struct PAC_LOGON_INFO *info = NULL;
2580         TALLOC_CTX *mem_ctx = NULL;
2581         NTSTATUS status;
2582         int ret = -1;
2583         const char *impersonate_princ_s = NULL;
2584
2585         if (c->display_usage) {
2586                 d_printf(  "%s\n"
2587                            "net ads kerberos pac\n"
2588                            "    %s\n",
2589                          _("Usage:"),
2590                          _("Dump the Kerberos PAC"));
2591                 return 0;
2592         }
2593
2594         mem_ctx = talloc_init("net_ads_kerberos_pac");
2595         if (!mem_ctx) {
2596                 goto out;
2597         }
2598
2599         if (argc > 0) {
2600                 impersonate_princ_s = argv[0];
2601         }
2602
2603         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2604
2605         status = kerberos_return_pac(mem_ctx,
2606                                      c->opt_user_name,
2607                                      c->opt_password,
2608                                      0,
2609                                      NULL,
2610                                      NULL,
2611                                      NULL,
2612                                      true,
2613                                      true,
2614                                      2592000, /* one month */
2615                                      impersonate_princ_s,
2616                                      &info);
2617         if (!NT_STATUS_IS_OK(status)) {
2618                 d_printf(_("failed to query kerberos PAC: %s\n"),
2619                         nt_errstr(status));
2620                 goto out;
2621         }
2622
2623         if (info) {
2624                 const char *s;
2625                 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2626                 d_printf(_("The Pac: %s\n"), s);
2627         }
2628
2629         ret = 0;
2630  out:
2631         TALLOC_FREE(mem_ctx);
2632         return ret;
2633 }
2634
2635 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2636 {
2637         TALLOC_CTX *mem_ctx = NULL;
2638         int ret = -1;
2639         NTSTATUS status;
2640
2641         if (c->display_usage) {
2642                 d_printf(  "%s\n"
2643                            "net ads kerberos kinit\n"
2644                            "    %s\n",
2645                          _("Usage:"),
2646                          _("Get Ticket Granting Ticket (TGT) for the user"));
2647                 return 0;
2648         }
2649
2650         mem_ctx = talloc_init("net_ads_kerberos_kinit");
2651         if (!mem_ctx) {
2652                 goto out;
2653         }
2654
2655         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2656
2657         ret = kerberos_kinit_password_ext(c->opt_user_name,
2658                                           c->opt_password,
2659                                           0,
2660                                           NULL,
2661                                           NULL,
2662                                           NULL,
2663                                           true,
2664                                           true,
2665                                           2592000, /* one month */
2666                                           &status);
2667         if (ret) {
2668                 d_printf(_("failed to kinit password: %s\n"),
2669                         nt_errstr(status));
2670         }
2671  out:
2672         return ret;
2673 }
2674
2675 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2676 {
2677         struct functable func[] = {
2678                 {
2679                         "kinit",
2680                         net_ads_kerberos_kinit,
2681                         NET_TRANSPORT_ADS,
2682                         N_("Retrieve Ticket Granting Ticket (TGT)"),
2683                         N_("net ads kerberos kinit\n"
2684                            "    Receive Ticket Granting Ticket (TGT)")
2685                 },
2686                 {
2687                         "renew",
2688                         net_ads_kerberos_renew,
2689                         NET_TRANSPORT_ADS,
2690                         N_("Renew Ticket Granting Ticket from credential cache"),
2691                         N_("net ads kerberos renew\n"
2692                            "    Renew Ticket Granting Ticket (TGT) from "
2693                            "credential cache")
2694                 },
2695                 {
2696                         "pac",
2697                         net_ads_kerberos_pac,
2698                         NET_TRANSPORT_ADS,
2699                         N_("Dump Kerberos PAC"),
2700                         N_("net ads kerberos pac\n"
2701                            "    Dump Kerberos PAC")
2702                 },
2703                 {NULL, NULL, 0, NULL, NULL}
2704         };
2705
2706         return net_run_function(c, argc, argv, "net ads kerberos", func);
2707 }
2708
2709 int net_ads(struct net_context *c, int argc, const char **argv)
2710 {
2711         struct functable func[] = {
2712                 {
2713                         "info",
2714                         net_ads_info,
2715                         NET_TRANSPORT_ADS,
2716                         N_("Display details on remote ADS server"),
2717                         N_("net ads info\n"
2718                            "    Display details on remote ADS server")
2719                 },
2720                 {
2721                         "join",
2722                         net_ads_join,
2723                         NET_TRANSPORT_ADS,
2724                         N_("Join the local machine to ADS realm"),
2725                         N_("net ads join\n"
2726                            "    Join the local machine to ADS realm")
2727                 },
2728                 {
2729                         "testjoin",
2730                         net_ads_testjoin,
2731                         NET_TRANSPORT_ADS,
2732                         N_("Validate machine account"),
2733                         N_("net ads testjoin\n"
2734                            "    Validate machine account")
2735                 },
2736                 {
2737                         "leave",
2738                         net_ads_leave,
2739                         NET_TRANSPORT_ADS,
2740                         N_("Remove the local machine from ADS"),
2741                         N_("net ads leave\n"
2742                            "    Remove the local machine from ADS")
2743                 },
2744                 {
2745                         "status",
2746                         net_ads_status,
2747                         NET_TRANSPORT_ADS,
2748                         N_("Display machine account details"),
2749                         N_("net ads status\n"
2750                            "    Display machine account details")
2751                 },
2752                 {
2753                         "user",
2754                         net_ads_user,
2755                         NET_TRANSPORT_ADS,
2756                         N_("List/modify users"),
2757                         N_("net ads user\n"
2758                            "    List/modify users")
2759                 },
2760                 {
2761                         "group",
2762                         net_ads_group,
2763                         NET_TRANSPORT_ADS,
2764                         N_("List/modify groups"),
2765                         N_("net ads group\n"
2766                            "    List/modify groups")
2767                 },
2768                 {
2769                         "dns",
2770                         net_ads_dns,
2771                         NET_TRANSPORT_ADS,
2772                         N_("Issue dynamic DNS update"),
2773                         N_("net ads dns\n"
2774                            "    Issue dynamic DNS update")
2775                 },
2776                 {
2777                         "password",
2778                         net_ads_password,
2779                         NET_TRANSPORT_ADS,
2780                         N_("Change user passwords"),
2781                         N_("net ads password\n"
2782                            "    Change user passwords")
2783                 },
2784                 {
2785                         "changetrustpw",
2786                         net_ads_changetrustpw,
2787                         NET_TRANSPORT_ADS,
2788                         N_("Change trust account password"),
2789                         N_("net ads changetrustpw\n"
2790                            "    Change trust account password")
2791                 },
2792                 {
2793                         "printer",
2794                         net_ads_printer,
2795                         NET_TRANSPORT_ADS,
2796                         N_("List/modify printer entries"),
2797                         N_("net ads printer\n"
2798                            "    List/modify printer entries")
2799                 },
2800                 {
2801                         "search",
2802                         net_ads_search,
2803                         NET_TRANSPORT_ADS,
2804                         N_("Issue LDAP search using filter"),
2805                         N_("net ads search\n"
2806                            "    Issue LDAP search using filter")
2807                 },
2808                 {
2809                         "dn",
2810                         net_ads_dn,
2811                         NET_TRANSPORT_ADS,
2812                         N_("Issue LDAP search by DN"),
2813                         N_("net ads dn\n"
2814                            "    Issue LDAP search by DN")
2815                 },
2816                 {
2817                         "sid",
2818                         net_ads_sid,
2819                         NET_TRANSPORT_ADS,
2820                         N_("Issue LDAP search by SID"),
2821                         N_("net ads sid\n"
2822                            "    Issue LDAP search by SID")
2823                 },
2824                 {
2825                         "workgroup",
2826                         net_ads_workgroup,
2827                         NET_TRANSPORT_ADS,
2828                         N_("Display workgroup name"),
2829                         N_("net ads workgroup\n"
2830                            "    Display the workgroup name")
2831                 },
2832                 {
2833                         "lookup",
2834                         net_ads_lookup,
2835                         NET_TRANSPORT_ADS,
2836                         N_("Perfom CLDAP query on DC"),
2837                         N_("net ads lookup\n"
2838                            "    Find the ADS DC using CLDAP lookups")
2839                 },
2840                 {
2841                         "keytab",
2842                         net_ads_keytab,
2843                         NET_TRANSPORT_ADS,
2844                         N_("Manage local keytab file"),
2845                         N_("net ads keytab\n"
2846                            "    Manage local keytab file")
2847                 },
2848                 {
2849                         "gpo",
2850                         net_ads_gpo,
2851                         NET_TRANSPORT_ADS,
2852                         N_("Manage group policy objects"),
2853                         N_("net ads gpo\n"
2854                            "    Manage group policy objects")
2855                 },
2856                 {
2857                         "kerberos",
2858                         net_ads_kerberos,
2859                         NET_TRANSPORT_ADS,
2860                         N_("Manage kerberos keytab"),
2861                         N_("net ads kerberos\n"
2862                            "    Manage kerberos keytab")
2863                 },
2864                 {NULL, NULL, 0, NULL, NULL}
2865         };
2866
2867         return net_run_function(c, argc, argv, "net ads", func);
2868 }
2869
2870 #else
2871
2872 static int net_ads_noads(void)
2873 {
2874         d_fprintf(stderr, _("ADS support not compiled in\n"));
2875         return -1;
2876 }
2877
2878 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2879 {
2880         return net_ads_noads();
2881 }
2882
2883 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2884 {
2885         return net_ads_noads();
2886 }
2887
2888 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2889 {
2890         return net_ads_noads();
2891 }
2892
2893 int net_ads_join(struct net_context *c, int argc, const char **argv)
2894 {
2895         return net_ads_noads();
2896 }
2897
2898 int net_ads_user(struct net_context *c, int argc, const char **argv)
2899 {
2900         return net_ads_noads();
2901 }
2902
2903 int net_ads_group(struct net_context *c, int argc, const char **argv)
2904 {
2905         return net_ads_noads();
2906 }
2907
2908 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2909 {
2910         return net_ads_noads();
2911 }
2912
2913 /* this one shouldn't display a message */
2914 int net_ads_check(struct net_context *c)
2915 {
2916         return -1;
2917 }
2918
2919 int net_ads_check_our_domain(struct net_context *c)
2920 {
2921         return -1;
2922 }
2923
2924 int net_ads(struct net_context *c, int argc, const char **argv)
2925 {
2926         return net_ads_noads();
2927 }
2928
2929 #endif  /* HAVE_ADS */