root/source3/utils/net_rpc_join.c

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

DEFINITIONS

This source file includes following definitions.
  1. net_rpc_join_ok
  2. net_rpc_join_newstyle
  3. net_rpc_testjoin

   1 /*
   2    Samba Unix/Linux SMB client library
   3    Distributed SMB/CIFS Server Management Utility
   4    Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
   5    Copyright (C) Tim Potter     2001
   6    Copyright (C) 2008 Guenther Deschner
   7 
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12 
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17 
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
  20 
  21 #include "includes.h"
  22 #include "utils/net.h"
  23 
  24 /* Macro for checking RPC error codes to make things more readable */
  25 
  26 #define CHECK_RPC_ERR(rpc, msg) \
  27         if (!NT_STATUS_IS_OK(result = rpc)) { \
  28                 DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
  29                 goto done; \
  30         }
  31 
  32 #define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
  33         if (!NT_STATUS_IS_OK(result = rpc)) { \
  34                 DEBUG(0, debug_args); \
  35                 goto done; \
  36         }
  37 
  38 /**
  39  * confirm that a domain join is still valid
  40  *
  41  * @return A shell status integer (0 for success)
  42  *
  43  **/
  44 NTSTATUS net_rpc_join_ok(struct net_context *c, const char *domain,
     /* [<][>][^][v][top][bottom][index][help] */
  45                          const char *server, struct sockaddr_storage *pss)
  46 {
  47         enum security_types sec;
  48         unsigned int conn_flags = NET_FLAGS_PDC;
  49         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
  50         struct cli_state *cli = NULL;
  51         struct rpc_pipe_client *pipe_hnd = NULL;
  52         struct rpc_pipe_client *netlogon_pipe = NULL;
  53         NTSTATUS ntret = NT_STATUS_UNSUCCESSFUL;
  54 
  55         sec = (enum security_types)lp_security();
  56 
  57         if (sec == SEC_ADS) {
  58                 /* Connect to IPC$ using machine account's credentials. We don't use anonymous
  59                    connection here, as it may be denied by server's local policy. */
  60                 net_use_machine_account(c);
  61 
  62         } else {
  63                 /* some servers (e.g. WinNT) don't accept machine-authenticated
  64                    smb connections */
  65                 conn_flags |= NET_FLAGS_ANONYMOUS;
  66         }
  67 
  68         /* Connect to remote machine */
  69         ntret = net_make_ipc_connection_ex(c, domain, server, pss, conn_flags,
  70                                            &cli);
  71         if (!NT_STATUS_IS_OK(ntret)) {
  72                 return ntret;
  73         }
  74 
  75         /* Setup the creds as though we're going to do schannel... */
  76         ntret = get_schannel_session_key(cli, domain, &neg_flags,
  77                                          &netlogon_pipe);
  78 
  79         /* We return NT_STATUS_INVALID_NETWORK_RESPONSE if the server is refusing
  80            to negotiate schannel, but the creds were set up ok. That'll have to do. */
  81 
  82         if (!NT_STATUS_IS_OK(ntret)) {
  83                 if (NT_STATUS_EQUAL(ntret, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
  84                         cli_shutdown(cli);
  85                         return NT_STATUS_OK;
  86                 } else {
  87                         DEBUG(0,("net_rpc_join_ok: failed to get schannel session "
  88                                         "key from server %s for domain %s. Error was %s\n",
  89                                 cli->desthost, domain, nt_errstr(ntret) ));
  90                         cli_shutdown(cli);
  91                         return ntret;
  92                 }
  93         }
  94 
  95         /* Only do the rest of the schannel test if the client is allowed to do this. */
  96         if (!lp_client_schannel()) {
  97                 cli_shutdown(cli);
  98                 /* We're good... */
  99                 return ntret;
 100         }
 101 
 102         ntret = cli_rpc_pipe_open_schannel_with_key(
 103                 cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
 104                 PIPE_AUTH_LEVEL_PRIVACY,
 105                 domain, netlogon_pipe->dc, &pipe_hnd);
 106 
 107         if (!NT_STATUS_IS_OK(ntret)) {
 108                 DEBUG(0,("net_rpc_join_ok: failed to open schannel session "
 109                                 "on netlogon pipe to server %s for domain %s. Error was %s\n",
 110                         cli->desthost, domain, nt_errstr(ntret) ));
 111                 /*
 112                  * Note: here, we have:
 113                  * (pipe_hnd != NULL) if and only if NT_STATUS_IS_OK(ntret)
 114                  */
 115         }
 116 
 117         cli_shutdown(cli);
 118         return ntret;
 119 }
 120 
 121 /**
 122  * Join a domain using the administrator username and password
 123  *
 124  * @param argc  Standard main() style argc
 125  * @param argc  Standard main() style argv.  Initial components are already
 126  *              stripped.  Currently not used.
 127  * @return A shell status integer (0 for success)
 128  *
 129  **/
 130 
 131 int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv)
     /* [<][>][^][v][top][bottom][index][help] */
 132 {
 133 
 134         /* libsmb variables */
 135 
 136         struct cli_state *cli;
 137         TALLOC_CTX *mem_ctx;
 138         uint32 acb_info = ACB_WSTRUST;
 139         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
 140         uint32 sec_channel_type;
 141         struct rpc_pipe_client *pipe_hnd = NULL;
 142 
 143         /* rpc variables */
 144 
 145         struct policy_handle lsa_pol, sam_pol, domain_pol, user_pol;
 146         DOM_SID *domain_sid;
 147         uint32 user_rid;
 148 
 149         /* Password stuff */
 150 
 151         char *clear_trust_password = NULL;
 152         struct samr_CryptPassword crypt_pwd;
 153         uchar md4_trust_password[16];
 154         union samr_UserInfo set_info;
 155 
 156         /* Misc */
 157 
 158         NTSTATUS result;
 159         int retval = 1;
 160         const char *domain = NULL;
 161         char *acct_name;
 162         struct lsa_String lsa_acct_name;
 163         uint32 acct_flags=0;
 164         uint32_t access_granted = 0;
 165         union lsa_PolicyInformation *info = NULL;
 166         struct samr_Ids user_rids;
 167         struct samr_Ids name_types;
 168 
 169         /* check what type of join */
 170         if (argc >= 0) {
 171                 sec_channel_type = get_sec_channel_type(argv[0]);
 172         } else {
 173                 sec_channel_type = get_sec_channel_type(NULL);
 174         }
 175 
 176         switch (sec_channel_type) {
 177         case SEC_CHAN_WKSTA:
 178                 acb_info = ACB_WSTRUST;
 179                 break;
 180         case SEC_CHAN_BDC:
 181                 acb_info = ACB_SVRTRUST;
 182                 break;
 183 #if 0
 184         case SEC_CHAN_DOMAIN:
 185                 acb_info = ACB_DOMTRUST;
 186                 break;
 187 #endif
 188         }
 189 
 190         /* Make authenticated connection to remote machine */
 191 
 192         result = net_make_ipc_connection(c, NET_FLAGS_PDC, &cli);
 193         if (!NT_STATUS_IS_OK(result)) {
 194                 return 1;
 195         }
 196 
 197         if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) {
 198                 DEBUG(0, ("Could not initialise talloc context\n"));
 199                 goto done;
 200         }
 201 
 202         /* Fetch domain sid */
 203 
 204         result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
 205                                           &pipe_hnd);
 206         if (!NT_STATUS_IS_OK(result)) {
 207                 DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
 208                         nt_errstr(result) ));
 209                 goto done;
 210         }
 211 
 212 
 213         CHECK_RPC_ERR(rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
 214                                           SEC_FLAG_MAXIMUM_ALLOWED,
 215                                           &lsa_pol),
 216                       "error opening lsa policy handle");
 217 
 218         CHECK_RPC_ERR(rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
 219                                                  &lsa_pol,
 220                                                  LSA_POLICY_INFO_ACCOUNT_DOMAIN,
 221                                                  &info),
 222                       "error querying info policy");
 223 
 224         domain = info->account_domain.name.string;
 225         domain_sid = info->account_domain.sid;
 226 
 227         rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
 228         TALLOC_FREE(pipe_hnd); /* Done with this pipe */
 229 
 230         /* Bail out if domain didn't get set. */
 231         if (!domain) {
 232                 DEBUG(0, ("Could not get domain name.\n"));
 233                 goto done;
 234         }
 235 
 236         /* Create domain user */
 237         result = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
 238                                           &pipe_hnd);
 239         if (!NT_STATUS_IS_OK(result)) {
 240                 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
 241                         nt_errstr(result) ));
 242                 goto done;
 243         }
 244 
 245         CHECK_RPC_ERR(rpccli_samr_Connect2(pipe_hnd, mem_ctx,
 246                                            pipe_hnd->desthost,
 247                                            SAMR_ACCESS_ENUM_DOMAINS
 248                                            | SAMR_ACCESS_LOOKUP_DOMAIN,
 249                                            &sam_pol),
 250                       "could not connect to SAM database");
 251 
 252 
 253         CHECK_RPC_ERR(rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
 254                                              &sam_pol,
 255                                              SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
 256                                              | SAMR_DOMAIN_ACCESS_CREATE_USER
 257                                              | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
 258                                              domain_sid,
 259                                              &domain_pol),
 260                       "could not open domain");
 261 
 262         /* Create domain user */
 263         if ((acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname())) == NULL) {
 264                 result = NT_STATUS_NO_MEMORY;
 265                 goto done;
 266         }
 267         strlower_m(acct_name);
 268 
 269         init_lsa_String(&lsa_acct_name, acct_name);
 270 
 271         acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
 272                      SEC_STD_WRITE_DAC | SEC_STD_DELETE |
 273                      SAMR_USER_ACCESS_SET_PASSWORD |
 274                      SAMR_USER_ACCESS_GET_ATTRIBUTES |
 275                      SAMR_USER_ACCESS_SET_ATTRIBUTES;
 276 
 277         DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
 278 
 279         result = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
 280                                          &domain_pol,
 281                                          &lsa_acct_name,
 282                                          acb_info,
 283                                          acct_flags,
 284                                          &user_pol,
 285                                          &access_granted,
 286                                          &user_rid);
 287 
 288         if (!NT_STATUS_IS_OK(result) && 
 289             !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) {
 290                 d_fprintf(stderr, "Creation of workstation account failed\n");
 291 
 292                 /* If NT_STATUS_ACCESS_DENIED then we have a valid
 293                    username/password combo but the user does not have
 294                    administrator access. */
 295 
 296                 if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
 297                         d_fprintf(stderr, "User specified does not have administrator privileges\n");
 298 
 299                 goto done;
 300         }
 301 
 302         /* We *must* do this.... don't ask... */
 303 
 304         if (NT_STATUS_IS_OK(result)) {
 305                 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
 306         }
 307 
 308         CHECK_RPC_ERR_DEBUG(rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
 309                                                     &domain_pol,
 310                                                     1,
 311                                                     &lsa_acct_name,
 312                                                     &user_rids,
 313                                                     &name_types),
 314                             ("error looking up rid for user %s: %s\n",
 315                              acct_name, nt_errstr(result)));
 316 
 317         if (name_types.ids[0] != SID_NAME_USER) {
 318                 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0]));
 319                 goto done;
 320         }
 321 
 322         user_rid = user_rids.ids[0];
 323 
 324         /* Open handle on user */
 325 
 326         CHECK_RPC_ERR_DEBUG(
 327                 rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
 328                                      &domain_pol,
 329                                      SEC_FLAG_MAXIMUM_ALLOWED,
 330                                      user_rid,
 331                                      &user_pol),
 332                 ("could not re-open existing user %s: %s\n",
 333                  acct_name, nt_errstr(result)));
 334         
 335         /* Create a random machine account password */
 336 
 337         clear_trust_password = generate_random_str(talloc_tos(), DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
 338         E_md4hash(clear_trust_password, md4_trust_password);
 339 
 340         /* Set password on machine account */
 341 
 342         init_samr_CryptPassword(clear_trust_password,
 343                                 &cli->user_session_key,
 344                                 &crypt_pwd);
 345 
 346         set_info.info24.password = crypt_pwd;
 347         set_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
 348 
 349         CHECK_RPC_ERR(rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
 350                                                &user_pol,
 351                                                24,
 352                                                &set_info),
 353                       "error setting trust account password");
 354 
 355         /* Why do we have to try to (re-)set the ACB to be the same as what
 356            we passed in the samr_create_dom_user() call?  When a NT
 357            workstation is joined to a domain by an administrator the
 358            acb_info is set to 0x80.  For a normal user with "Add
 359            workstations to the domain" rights the acb_info is 0x84.  I'm
 360            not sure whether it is supposed to make a difference or not.  NT
 361            seems to cope with either value so don't bomb out if the set
 362            userinfo2 level 0x10 fails.  -tpot */
 363 
 364         set_info.info16.acct_flags = acb_info;
 365 
 366         /* Ignoring the return value is necessary for joining a domain
 367            as a normal user with "Add workstation to domain" privilege. */
 368 
 369         result = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
 370                                          &user_pol,
 371                                          16,
 372                                          &set_info);
 373 
 374         rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
 375         TALLOC_FREE(pipe_hnd); /* Done with this pipe */
 376 
 377         /* Now check the whole process from top-to-bottom */
 378 
 379         result = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
 380                                           &pipe_hnd);
 381         if (!NT_STATUS_IS_OK(result)) {
 382                 DEBUG(0,("Error connecting to NETLOGON pipe. Error was %s\n",
 383                         nt_errstr(result) ));
 384                 goto done;
 385         }
 386 
 387         result = rpccli_netlogon_setup_creds(pipe_hnd,
 388                                         cli->desthost, /* server name */
 389                                         domain,        /* domain */
 390                                         global_myname(), /* client name */
 391                                         global_myname(), /* machine account name */
 392                                         md4_trust_password,
 393                                         sec_channel_type,
 394                                         &neg_flags);
 395 
 396         if (!NT_STATUS_IS_OK(result)) {
 397                 DEBUG(0, ("Error in domain join verification (credential setup failed): %s\n\n",
 398                           nt_errstr(result)));
 399 
 400                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) &&
 401                      (sec_channel_type == SEC_CHAN_BDC) ) {
 402                         d_fprintf(stderr, "Please make sure that no computer account\n"
 403                                  "named like this machine (%s) exists in the domain\n",
 404                                  global_myname());
 405                 }
 406 
 407                 goto done;
 408         }
 409 
 410         /* We can only check the schannel connection if the client is allowed
 411            to do this and the server supports it. If not, just assume success
 412            (after all the rpccli_netlogon_setup_creds() succeeded, and we'll
 413            do the same again (setup creds) in net_rpc_join_ok(). JRA. */
 414 
 415         if (lp_client_schannel() && (neg_flags & NETLOGON_NEG_SCHANNEL)) {
 416                 struct rpc_pipe_client *netlogon_schannel_pipe;
 417 
 418                 result = cli_rpc_pipe_open_schannel_with_key(
 419                         cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
 420                         PIPE_AUTH_LEVEL_PRIVACY, domain, pipe_hnd->dc,
 421                         &netlogon_schannel_pipe);
 422 
 423                 if (!NT_STATUS_IS_OK(result)) {
 424                         DEBUG(0, ("Error in domain join verification (schannel setup failed): %s\n\n",
 425                                   nt_errstr(result)));
 426 
 427                         if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) &&
 428                              (sec_channel_type == SEC_CHAN_BDC) ) {
 429                                 d_fprintf(stderr, "Please make sure that no computer account\n"
 430                                          "named like this machine (%s) exists in the domain\n",
 431                                          global_myname());
 432                         }
 433 
 434                         goto done;
 435                 }
 436                 TALLOC_FREE(netlogon_schannel_pipe);
 437         }
 438 
 439         TALLOC_FREE(pipe_hnd);
 440 
 441         /* Now store the secret in the secrets database */
 442 
 443         strupper_m(CONST_DISCARD(char *, domain));
 444 
 445         if (!secrets_store_domain_sid(domain, domain_sid)) {
 446                 DEBUG(0, ("error storing domain sid for %s\n", domain));
 447                 goto done;
 448         }
 449 
 450         if (!secrets_store_machine_password(clear_trust_password, domain, sec_channel_type)) {
 451                 DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain));
 452         }
 453 
 454         /* double-check, connection from scratch */
 455         result = net_rpc_join_ok(c, domain, cli->desthost, &cli->dest_ss);
 456         retval = NT_STATUS_IS_OK(result) ? 0 : -1;
 457 
 458 done:
 459 
 460         /* Display success or failure */
 461 
 462         if (domain) {
 463                 if (retval != 0) {
 464                         fprintf(stderr,"Unable to join domain %s.\n",domain);
 465                 } else {
 466                         printf("Joined domain %s.\n",domain);
 467                 }
 468         }
 469 
 470         cli_shutdown(cli);
 471 
 472         TALLOC_FREE(clear_trust_password);
 473 
 474         return retval;
 475 }
 476 
 477 /**
 478  * check that a join is OK
 479  *
 480  * @return A shell status integer (0 for success)
 481  *
 482  **/
 483 int net_rpc_testjoin(struct net_context *c, int argc, const char **argv)
     /* [<][>][^][v][top][bottom][index][help] */
 484 {
 485         NTSTATUS nt_status;
 486 
 487         if (c->display_usage) {
 488                 d_printf("Usage\n"
 489                          "net rpc testjoin\n"
 490                          "    Test if a join is OK\n");
 491                 return 0;
 492         }
 493 
 494         /* Display success or failure */
 495         nt_status = net_rpc_join_ok(c, c->opt_target_workgroup, NULL, NULL);
 496         if (!NT_STATUS_IS_OK(nt_status)) {
 497                 fprintf(stderr,"Join to domain '%s' is not valid: %s\n",
 498                         c->opt_target_workgroup, nt_errstr(nt_status));
 499                 return -1;
 500         }
 501 
 502         printf("Join to '%s' is OK\n", c->opt_target_workgroup);
 503         return 0;
 504 }

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