root/source3/utils/net_ads.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. assume_own_realm
  2. net_ads_cldap_netlogon
  3. net_ads_lookup
  4. net_ads_info
  5. use_in_memory_ccache
  6. ads_startup_int
  7. ads_startup
  8. ads_startup_nobind
  9. net_ads_check_int
  10. net_ads_check_our_domain
  11. net_ads_check
  12. net_ads_workgroup
  13. usergrp_display
  14. net_ads_user_usage
  15. ads_user_add
  16. ads_user_info
  17. ads_user_delete
  18. net_ads_user
  19. net_ads_group_usage
  20. ads_group_add
  21. ads_group_delete
  22. net_ads_group
  23. net_ads_status
  24. net_ads_leave
  25. net_ads_join_ok
  26. net_ads_testjoin
  27. check_ads_config
  28. net_update_dns_internal
  29. net_update_dns
  30. net_ads_join_usage
  31. net_ads_join
  32. net_ads_dns_register
  33. net_ads_dns_gethostbyname
  34. net_ads_dns
  35. net_ads_printer_usage
  36. net_ads_printer_search
  37. net_ads_printer_info
  38. net_ads_printer_publish
  39. net_ads_printer_remove
  40. net_ads_printer
  41. net_ads_password
  42. net_ads_changetrustpw
  43. net_ads_search_usage
  44. net_ads_search
  45. net_ads_dn_usage
  46. net_ads_dn
  47. net_ads_sid_usage
  48. net_ads_sid
  49. net_ads_keytab_flush
  50. net_ads_keytab_add
  51. net_ads_keytab_create
  52. net_ads_keytab_list
  53. net_ads_keytab
  54. net_ads_kerberos_renew
  55. net_ads_kerberos_pac
  56. net_ads_kerberos_kinit
  57. net_ads_kerberos
  58. net_ads
  59. net_ads_noads
  60. net_ads_keytab
  61. net_ads_kerberos
  62. net_ads_changetrustpw
  63. net_ads_join
  64. net_ads_user
  65. net_ads_group
  66. net_ads_check
  67. net_ads_check_our_domain
  68. net_ads

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

/* [<][>][^][v][top][bottom][index][help] */