LCOV - code coverage report
Current view: top level - source3/utils - net_offlinejoin.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 0 300 0.0 %
Date: 2024-02-14 10:14:15 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /*
       2             :    Samba Unix/Linux SMB client library
       3             :    net join commands
       4             :    Copyright (C) 2021 Guenther Deschner (gd@samba.org)
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "utils/net.h"
      22             : #include <netapi.h>
      23             : #include "netapi/netapi_net.h"
      24             : #include "libcli/registry/util_reg.h"
      25             : #include "libcli/security/dom_sid.h"
      26             : #include "lib/cmdline/cmdline.h"
      27             : 
      28           0 : int net_offlinejoin_usage(struct net_context *c, int argc, const char **argv)
      29             : {
      30           0 :         d_printf(_("\nnet offlinejoin [misc. options]\n"
      31             :                    "\tjoins a computer to a domain\n"));
      32           0 :         d_printf(_("Valid commands:\n"));
      33           0 :         d_printf(_("\tprovision\t\t\tProvision machine account in AD\n"));
      34           0 :         d_printf(_("\trequestodj\t\t\tRequest offline domain join\n"));
      35           0 :         d_printf(_("\tcomposeodj\t\t\tCompose offline domain join blob\n"));
      36           0 :         net_common_flags_usage(c, argc, argv);
      37           0 :         return -1;
      38             : }
      39             : 
      40           0 : int net_offlinejoin(struct net_context *c, int argc, const char **argv)
      41             : {
      42             :         int ret;
      43             :         NET_API_STATUS status;
      44             : 
      45           0 :         if ((argc > 0) && (strcasecmp_m(argv[0], "HELP") == 0)) {
      46           0 :                 net_offlinejoin_usage(c, argc, argv);
      47           0 :                 return 0;
      48             :         }
      49             : 
      50           0 :         if (argc == 0) {
      51           0 :                 net_offlinejoin_usage(c, argc, argv);
      52           0 :                 return -1;
      53             :         }
      54             : 
      55           0 :         net_warn_member_options();
      56             : 
      57           0 :         status = libnetapi_net_init(&c->netapi_ctx);
      58           0 :         if (status != 0) {
      59           0 :                 return -1;
      60             :         }
      61             : 
      62           0 :         status = libnetapi_set_creds(c->netapi_ctx, c->creds);
      63           0 :         if (status != 0) {
      64           0 :                 return -1;
      65             :         }
      66             : 
      67           0 :         if (c->opt_kerberos) {
      68           0 :                 libnetapi_set_use_kerberos(c->netapi_ctx);
      69             :         }
      70             : 
      71           0 :         if (strcasecmp_m(argv[0], "provision") == 0) {
      72           0 :                 ret = net_offlinejoin_provision(c, argc, argv);
      73           0 :                 if (ret != 0) {
      74           0 :                         return ret;
      75             :                 }
      76             :         }
      77             : 
      78           0 :         if (strcasecmp_m(argv[0], "requestodj") == 0) {
      79           0 :                 ret = net_offlinejoin_requestodj(c, argc, argv);
      80           0 :                 if (ret != 0) {
      81           0 :                         return ret;
      82             :                 }
      83             :         }
      84             : 
      85           0 :         if (strcasecmp_m(argv[0], "composeodj") == 0) {
      86           0 :                 ret = net_offlinejoin_composeodj(c, argc, argv);
      87           0 :                 if (ret != 0) {
      88           0 :                         return ret;
      89             :                 }
      90             :         }
      91             : 
      92           0 :         return 0;
      93             : }
      94             : 
      95           0 : static int net_offlinejoin_provision_usage(struct net_context *c, int argc, const char **argv)
      96             : {
      97           0 :         d_printf(_("\nnet offlinejoin provision [misc. options]\n"
      98             :                    "\tProvisions machine account in AD\n"));
      99           0 :         d_printf(_("Valid options:\n"));
     100           0 :         d_printf(_("\tdomain=<DOMAIN>\t\t\t\tDefines AD Domain to join\n"));
     101           0 :         d_printf(_("\tmachine_name=<MACHINE_NAME>\t\tDefines the machine account name\n"));
     102           0 :         d_printf(_("\tmachine_account_ou=<OU>\t\t\tDefines the machine account organizational unit DN\n"));
     103           0 :         d_printf(_("\tdcname=<DCNAME>\t\t\t\tSpecifices a Domain Controller to join to\n"));
     104           0 :         d_printf(_("\tdefpwd\t\t\t\t\tUse default machine account password\n"));
     105           0 :         d_printf(_("\treuse\t\t\t\t\tReuse existing machine account in AD\n"));
     106           0 :         d_printf(_("\tsavefile=<FILENAME>\t\t\tFile to store the ODJ data\n"));
     107           0 :         d_printf(_("\tprintblob\t\t\t\tPrint the base64 encoded ODJ data on stdout\n"));
     108           0 :         net_common_flags_usage(c, argc, argv);
     109           0 :         return -1;
     110             : }
     111             : 
     112           0 : int net_offlinejoin_provision(struct net_context *c,
     113             :                               int argc, const char **argv)
     114             : {
     115             :         NET_API_STATUS status;
     116           0 :         const char *dcname = NULL;
     117           0 :         const char *domain = NULL;
     118           0 :         const char *machine_name = NULL;
     119           0 :         const char *machine_account_ou = NULL;
     120           0 :         const char *provision_text_data = NULL;
     121           0 :         uint32_t options = 0;
     122           0 :         const char *savefile = NULL;
     123           0 :         bool printblob = false;
     124             :         int i;
     125             : 
     126           0 :         if (c->display_usage || argc == 1) {
     127           0 :                 return net_offlinejoin_provision_usage(c, argc, argv);
     128             :         }
     129             : 
     130             :         /* process additional command line args */
     131             : 
     132           0 :         for (i = 0; i < argc; i++) {
     133             : 
     134           0 :                 if (strnequal(argv[i], "domain", strlen("domain"))) {
     135           0 :                         domain = get_string_param(argv[i]);
     136           0 :                         if (domain == NULL) {
     137           0 :                                 return -1;
     138             :                         }
     139             :                 }
     140           0 :                 if (strnequal(argv[i], "machine_name", strlen("machine_name"))) {
     141           0 :                         machine_name = get_string_param(argv[i]);
     142           0 :                         if (machine_name == NULL) {
     143           0 :                                 return -1;
     144             :                         }
     145             :                 }
     146           0 :                 if (strnequal(argv[i], "machine_account_ou", strlen("machine_account_ou"))) {
     147           0 :                         machine_account_ou = get_string_param(argv[i]);
     148           0 :                         if (machine_account_ou == NULL) {
     149           0 :                                 return -1;
     150             :                         }
     151             :                 }
     152           0 :                 if (strnequal(argv[i], "dcname", strlen("dcname"))) {
     153           0 :                         dcname = get_string_param(argv[i]);
     154           0 :                         if (dcname == NULL) {
     155           0 :                                 return -1;
     156             :                         }
     157             :                 }
     158           0 :                 if (strnequal(argv[i], "defpwd", strlen("defpwd"))) {
     159           0 :                         options |= NETSETUP_PROVISION_USE_DEFAULT_PASSWORD;
     160             :                 }
     161           0 :                 if (strnequal(argv[i], "reuse", strlen("reuse"))) {
     162           0 :                         options |= NETSETUP_PROVISION_REUSE_ACCOUNT;
     163             :                 }
     164           0 :                 if (strnequal(argv[i], "savefile", strlen("savefile"))) {
     165           0 :                         savefile = get_string_param(argv[i]);
     166           0 :                         if (savefile == NULL) {
     167           0 :                                 return -1;
     168             :                         }
     169             :                 }
     170           0 :                 if (strnequal(argv[i], "printblob", strlen("printblob"))) {
     171           0 :                         printblob = true;
     172             :                 }
     173             :         }
     174             : 
     175           0 :         if (domain == NULL) {
     176           0 :                 d_printf("Failed to provision computer account: %s\n",
     177           0 :                          libnetapi_errstr(W_ERROR_V(WERR_INVALID_DOMAINNAME)));
     178           0 :                 return -1;
     179             :         }
     180             : 
     181           0 :         if (machine_name == NULL) {
     182           0 :                 d_printf("Failed to provision computer account: %s\n",
     183           0 :                          libnetapi_errstr(W_ERROR_V(WERR_INVALID_COMPUTERNAME)));
     184           0 :                 return -1;
     185             :         }
     186             : 
     187           0 :         status = NetProvisionComputerAccount(domain,
     188             :                                              machine_name,
     189             :                                              machine_account_ou,
     190             :                                              dcname,
     191             :                                              options,
     192             :                                              NULL,
     193             :                                              0,
     194             :                                              &provision_text_data);
     195           0 :         if (status != 0) {
     196           0 :                 d_printf("Failed to provision computer account: %s\n",
     197             :                         libnetapi_get_error_string(c->netapi_ctx, status));
     198           0 :                 return status;
     199             :         }
     200             : 
     201           0 :         if (savefile != NULL) {
     202             : 
     203             :                 DATA_BLOB ucs2_blob, blob;
     204             :                 bool ok;
     205             : 
     206             :                 /*
     207             :                  * Windows produces and consumes UTF16/UCS2 encoded blobs
     208             :                  * so we also do it for compatibility. Someone may provision an
     209             :                  * account for a Windows machine with samba.
     210             :                  */
     211           0 :                 ok = push_reg_sz(c, &ucs2_blob, provision_text_data);
     212           0 :                 if (!ok) {
     213           0 :                         return -1;
     214             :                 }
     215             : 
     216             :                 /* Add the unicode BOM mark */
     217           0 :                 blob = data_blob_talloc(c, NULL, ucs2_blob.length + 2);
     218             : 
     219           0 :                 blob.data[0] = 0xff;
     220           0 :                 blob.data[1] = 0xfe;
     221             : 
     222           0 :                 memcpy(blob.data + 2, ucs2_blob.data, ucs2_blob.length);
     223             : 
     224           0 :                 ok = file_save(savefile, blob.data, blob.length);
     225           0 :                 if (!ok) {
     226           0 :                         d_printf("Failed to save %s: %s\n", savefile,
     227           0 :                                         strerror(errno));
     228           0 :                         return -1;
     229             :                 }
     230             :         }
     231             : 
     232           0 :         d_printf("Successfully provisioned computer '%s' in domain '%s'\n",
     233             :                         machine_name, domain);
     234             : 
     235           0 :         if (printblob) {
     236           0 :                 printf("%s\n", provision_text_data);
     237             :         }
     238             : 
     239           0 :         return 0;
     240             : }
     241             : 
     242           0 : static int net_offlinejoin_requestodj_usage(struct net_context *c, int argc, const char **argv)
     243             : {
     244           0 :         d_printf(_("\nnet offlinejoin requestodj [misc. options]\n"
     245             :                    "\tRequests offline domain join\n"));
     246           0 :         d_printf(_("Valid options:\n"));
     247           0 :         d_printf(_("\t-i\t\t\t\t\tRead ODJ data from STDIN\n"));
     248           0 :         d_printf(_("\tloadfile=<FILENAME>\t\t\tFile that provides the ODJ data\n"));
     249             :         /*d_printf(_("\tlocalos\t\t\t\t\tModify the local machine\n"));*/
     250           0 :         net_common_flags_usage(c, argc, argv);
     251           0 :         return -1;
     252             : }
     253             : 
     254           0 : int net_offlinejoin_requestodj(struct net_context *c,
     255             :                                int argc, const char **argv)
     256             : {
     257             :         NET_API_STATUS status;
     258           0 :         uint8_t *provision_bin_data = NULL;
     259           0 :         size_t provision_bin_data_size = 0;
     260           0 :         uint32_t options = NETSETUP_PROVISION_ONLINE_CALLER;
     261           0 :         const char *windows_path = NULL;
     262             :         int i;
     263             : 
     264           0 :         if (c->display_usage) {
     265           0 :                 return net_offlinejoin_requestodj_usage(c, argc, argv);
     266             :         }
     267             : 
     268             :         /* process additional command line args */
     269             : 
     270           0 :         for (i = 0; i < argc; i++) {
     271             : 
     272           0 :                 if (strnequal(argv[i], "loadfile", strlen("loadfile"))) {
     273           0 :                         const char *loadfile = NULL;
     274             : 
     275           0 :                         loadfile = get_string_param(argv[i]);
     276           0 :                         if (loadfile == NULL) {
     277           0 :                                 return -1;
     278             :                         }
     279             : 
     280             :                         provision_bin_data =
     281           0 :                                 (uint8_t *)file_load(loadfile,
     282             :                                                      &provision_bin_data_size,
     283             :                                                      0,
     284             :                                                      c);
     285           0 :                         if (provision_bin_data == NULL) {
     286           0 :                                 d_printf("Failed to read loadfile: %s\n",
     287             :                                 loadfile);
     288           0 :                                 return -1;
     289             :                         }
     290             :                 }
     291             : #if 0
     292             :                 if (strnequal(argv[i], "localos", strlen("localos"))) {
     293             :                         options |= NETSETUP_PROVISION_ONLINE_CALLER;
     294             :                 }
     295             : #endif
     296             :         }
     297             : 
     298           0 :         if (c->opt_stdin) {
     299           0 :                 if (isatty(STDIN_FILENO) == 1) {
     300           0 :                         d_fprintf(stderr,
     301             :                                   "hint: stdin waiting for ODJ blob, end "
     302             :                                   "with <crtl-D>.\n");
     303             :                 }
     304             :                 provision_bin_data =
     305           0 :                         (uint8_t *)fd_load(STDIN_FILENO,
     306             :                                            &provision_bin_data_size, 0, c);
     307           0 :                 if (provision_bin_data == NULL) {
     308           0 :                         d_printf("Failed to read ODJ blob from stdin\n");
     309           0 :                         return -1;
     310             :                 }
     311             : 
     312             :                 /* Strip last newline */
     313           0 :                 if (provision_bin_data[provision_bin_data_size - 1] == '\n') {
     314           0 :                         provision_bin_data[provision_bin_data_size - 1] = '\0';
     315             :                 }
     316             :         }
     317             : 
     318           0 :         if (provision_bin_data == NULL || provision_bin_data_size == 0) {
     319           0 :                 d_printf("Please provide provision data either from file "
     320             :                          "(using loadfile parameter) of from stdin (-i)\n");
     321           0 :                 return -1;
     322             :         }
     323           0 :         if (provision_bin_data_size > UINT32_MAX) {
     324           0 :                 d_printf("provision binary data size too big: %zu\n",
     325             :                          provision_bin_data_size);
     326           0 :                 return -1;
     327             :         }
     328             : 
     329           0 :         status = NetRequestOfflineDomainJoin(provision_bin_data,
     330             :                                              provision_bin_data_size,
     331             :                                              options,
     332             :                                              windows_path);
     333           0 :         if (status != 0 && status != 0x00000a99) {
     334             :                 /* NERR_JoinPerformedMustRestart */
     335           0 :                 printf("Failed to call NetRequestOfflineDomainJoin: %s\n",
     336             :                         libnetapi_get_error_string(c->netapi_ctx, status));
     337           0 :                 return -1;
     338             :         }
     339             : 
     340           0 :         d_printf("Successfully requested Offline Domain Join\n");
     341             : 
     342           0 :         return 0;
     343             : }
     344             : 
     345           0 : static int net_offlinejoin_composeodj_usage(struct net_context *c,
     346             :                                             int argc,
     347             :                                             const char **argv)
     348             : {
     349           0 :         d_printf(_("\nnet offlinejoin composeodj [misc. options]\n"
     350             :                    "\tComposes offline domain join blob\n"));
     351           0 :         d_printf(_("Valid options:\n"));
     352           0 :         d_printf(_("\tdomain_sid=<SID>\t\t\tThe domain SID\n"));
     353           0 :         d_printf(_("\tdomain_guid=<GUID>\t\t\tThe domain GUID\n"));
     354           0 :         d_printf(_("\tforest_name=<NAME>\t\t\tThe forest name\n"));
     355           0 :         d_printf(_("\tdomain_is_nt4\t\t\t\tThe domain not AD but NT4\n"));
     356           0 :         d_printf(_("\tsavefile=<FILENAME>\t\t\tFile to store the ODJ data\n"));
     357           0 :         d_printf(_("\tprintblob\t\t\t\tPrint the base64 encoded ODJ data on stdout\n"));
     358           0 :         net_common_flags_usage(c, argc, argv);
     359           0 :         d_printf(_("Example:\n"));
     360           0 :         d_printf("\tnet offlinejoin composeodj --realm=<realm> "
     361             :                  "--workgroup=<domain> domain_sid=<sid> domain_guid=<guid> "
     362             :                  "forest_name=<name> -S <dc name> -I <dc address> "
     363             :                  "--password=<password> printblob\n");
     364           0 :         return -1;
     365             : }
     366             : 
     367           0 : int net_offlinejoin_composeodj(struct net_context *c,
     368             :                                int argc,
     369             :                                const char **argv)
     370             : {
     371           0 :         struct cli_credentials *creds = samba_cmdline_get_creds();
     372             :         NET_API_STATUS status;
     373           0 :         const char *dns_domain_name = NULL;
     374           0 :         const char *netbios_domain_name = NULL;
     375           0 :         const char *machine_account_name = NULL;
     376           0 :         const char *machine_account_password = NULL;
     377           0 :         const char *domain_sid_str = NULL;
     378           0 :         const char *domain_guid_str = NULL;
     379             :         struct dom_sid domain_sid;
     380             :         struct GUID domain_guid;
     381           0 :         const char *forest_name = NULL;
     382           0 :         const char *dc_name = NULL;
     383           0 :         char dc_address[INET6_ADDRSTRLEN] = { 0 };
     384           0 :         bool domain_is_ad = true;
     385           0 :         const char *provision_text_data = NULL;
     386           0 :         const char *savefile = NULL;
     387           0 :         bool printblob = false;
     388             :         enum credentials_obtained obtained;
     389             :         bool ok;
     390             :         NTSTATUS ntstatus;
     391             :         int i;
     392             : 
     393           0 :         if (c->display_usage || argc < 4) {
     394           0 :                 return net_offlinejoin_composeodj_usage(c, argc, argv);
     395             :         }
     396             : 
     397           0 :         dns_domain_name = cli_credentials_get_realm(creds);
     398           0 :         netbios_domain_name = cli_credentials_get_domain(creds);
     399             : 
     400           0 :         machine_account_name = cli_credentials_get_username_and_obtained(creds, &obtained);
     401           0 :         if (obtained < CRED_CALLBACK_RESULT) {
     402           0 :                 const char *netbios_name = cli_credentials_get_workstation(creds);
     403           0 :                 cli_credentials_set_username(
     404             :                         creds,
     405           0 :                         talloc_asprintf(c, "%s$", netbios_name),
     406             :                         CRED_SPECIFIED);
     407             :         }
     408             : 
     409           0 :         machine_account_name = cli_credentials_get_username(creds);
     410           0 :         machine_account_password = cli_credentials_get_password(creds);
     411           0 :         dc_name = c->opt_host;
     412             : 
     413           0 :         if (c->opt_have_ip) {
     414           0 :                 struct sockaddr_in *in4 = NULL;
     415           0 :                 struct sockaddr_in6 *in6 = NULL;
     416           0 :                 const char *p = NULL;
     417             : 
     418           0 :                 switch(c->opt_dest_ip.ss_family) {
     419           0 :                 case AF_INET:
     420           0 :                         in4 = (struct sockaddr_in *)&c->opt_dest_ip;
     421           0 :                         p = inet_ntop(AF_INET, &in4->sin_addr, dc_address, sizeof(dc_address));
     422           0 :                         break;
     423           0 :                 case AF_INET6:
     424           0 :                         in6 = (struct sockaddr_in6 *)&c->opt_dest_ip;
     425           0 :                         p = inet_ntop(AF_INET6, &in6->sin6_addr, dc_address, sizeof(dc_address));
     426           0 :                         break;
     427           0 :                 default:
     428           0 :                         d_printf("Unknown IP address family\n");
     429           0 :                         return -1;
     430             :                 }
     431             : 
     432           0 :                 if (p == NULL) {
     433           0 :                         d_fprintf(stderr, "Failed to parse IP address: %s\n", strerror(errno));
     434           0 :                         return -1;
     435             :                 }
     436             :         }
     437             : 
     438             :         /* process additional command line args */
     439             : 
     440           0 :         for (i = 0; i < argc; i++) {
     441           0 :                 if (strnequal(argv[i], "domain_sid", strlen("domain_sid"))) {
     442           0 :                         domain_sid_str = get_string_param(argv[i]);
     443           0 :                         if (domain_sid_str == NULL) {
     444           0 :                                 return -1;
     445             :                         }
     446             :                 }
     447             : 
     448           0 :                 if (strnequal(argv[i], "domain_guid", strlen("domain_guid"))) {
     449           0 :                         domain_guid_str = get_string_param(argv[i]);
     450           0 :                         if (domain_guid_str == NULL) {
     451           0 :                                 return -1;
     452             :                         }
     453             :                 }
     454             : 
     455           0 :                 if (strnequal(argv[i], "forest_name", strlen("forest_name"))) {
     456           0 :                         forest_name = get_string_param(argv[i]);
     457           0 :                         if (forest_name == NULL) {
     458           0 :                                 return -1;
     459             :                         }
     460             :                 }
     461             : 
     462           0 :                 if (strnequal(argv[i], "savefile", strlen("savefile"))) {
     463           0 :                         savefile = get_string_param(argv[i]);
     464           0 :                         if (savefile == NULL) {
     465           0 :                                 return -1;
     466             :                         }
     467             :                 }
     468             : 
     469           0 :                 if (strnequal(argv[i], "printblob", strlen("printblob"))) {
     470           0 :                         printblob = true;
     471             :                 }
     472             : 
     473           0 :                 if (strnequal(argv[i], "domain_is_nt4", strlen("domain_is_nt4"))) {
     474           0 :                         domain_is_ad = false;
     475             :                 }
     476             :         }
     477             : 
     478             :         /* Check command line arguments */
     479             : 
     480           0 :         if (savefile == NULL && !printblob) {
     481           0 :                 d_printf("Choose either save the blob to a file or print it\n");
     482           0 :                 return -1;
     483             :         }
     484             : 
     485           0 :         if (dns_domain_name == NULL) {
     486           0 :                 d_printf("Please provide a valid realm parameter (--realm)\n");
     487           0 :                 return -1;
     488             :         }
     489             : 
     490           0 :         if (netbios_domain_name == NULL) {
     491           0 :                 d_printf("Please provide a valid domain parameter (--workgroup)\n");
     492           0 :                 return -1;
     493             :         }
     494             : 
     495           0 :         if (dc_name == NULL) {
     496           0 :                 d_printf("Please provide a valid DC name parameter (-S)\n");
     497           0 :                 return -1;
     498             :         }
     499             : 
     500           0 :         if (strlen(dc_address) == 0) {
     501           0 :                 d_printf("Please provide a valid domain controller address parameter (-I)\n");
     502           0 :                 return -1;
     503             :         }
     504             : 
     505           0 :         if (machine_account_name == NULL) {
     506           0 :                 d_printf("Please provide a valid netbios name parameter\n");
     507           0 :                 return -1;
     508             :         }
     509             : 
     510           0 :         if (machine_account_password == NULL) {
     511           0 :                 d_printf("Please provide a valid password parameter\n");
     512           0 :                 return -1;
     513             :         }
     514             : 
     515           0 :         if (domain_sid_str == NULL) {
     516           0 :                 d_printf("Please provide a valid <domain_sid> parameter\n");
     517           0 :                 return -1;
     518             :         }
     519             : 
     520           0 :         if (domain_guid_str == NULL) {
     521           0 :                 d_printf("Please provide a valid <domain_guid> parameter\n");
     522           0 :                 return -1;
     523             :         }
     524             : 
     525           0 :         if (forest_name == NULL) {
     526           0 :                 d_printf("Please provide a valid <forest_name> parameter\n");
     527           0 :                 return -1;
     528             :         }
     529             : 
     530           0 :         ok = dom_sid_parse(domain_sid_str, &domain_sid);
     531           0 :         if (!ok) {
     532           0 :                 d_fprintf(stderr, _("Failed to parse domain SID\n"));
     533           0 :                 return -1;
     534             :         }
     535             : 
     536           0 :         ntstatus = GUID_from_string(domain_guid_str, &domain_guid);
     537           0 :         if (NT_STATUS_IS_ERR(ntstatus)) {
     538           0 :                 d_fprintf(stderr, _("Failed to parse domain GUID\n"));
     539           0 :                 return -1;
     540             :         }
     541             : 
     542           0 :         status = NetComposeOfflineDomainJoin(dns_domain_name,
     543             :                                              netbios_domain_name,
     544             :                                              (struct domsid *)&domain_sid,
     545             :                                              &domain_guid,
     546             :                                              forest_name,
     547             :                                              machine_account_name,
     548             :                                              machine_account_password,
     549             :                                              dc_name,
     550             :                                              dc_address,
     551             :                                              domain_is_ad,
     552             :                                              NULL,
     553             :                                              0,
     554             :                                              &provision_text_data);
     555           0 :         if (status != 0) {
     556           0 :                 d_printf("Failed to compose offline domain join blob: %s\n",
     557             :                         libnetapi_get_error_string(c->netapi_ctx, status));
     558           0 :                 return status;
     559             :         }
     560             : 
     561           0 :         if (savefile != NULL) {
     562             :                 DATA_BLOB ucs2_blob, blob;
     563             : 
     564             :                 /*
     565             :                  * Windows produces and consumes UTF16/UCS2 encoded blobs
     566             :                  * so we also do it for compatibility. Someone may provision an
     567             :                  * account for a Windows machine with samba.
     568             :                  */
     569           0 :                 ok = push_reg_sz(c, &ucs2_blob, provision_text_data);
     570           0 :                 if (!ok) {
     571           0 :                         return -1;
     572             :                 }
     573             : 
     574             :                 /* Add the unicode BOM mark */
     575           0 :                 blob = data_blob_talloc(c, NULL, ucs2_blob.length + 2);
     576             : 
     577           0 :                 blob.data[0] = 0xff;
     578           0 :                 blob.data[1] = 0xfe;
     579             : 
     580           0 :                 memcpy(blob.data + 2, ucs2_blob.data, ucs2_blob.length);
     581             : 
     582           0 :                 ok = file_save(savefile, blob.data, blob.length);
     583           0 :                 if (!ok) {
     584           0 :                         d_printf("Failed to save %s: %s\n", savefile,
     585           0 :                                         strerror(errno));
     586           0 :                         return -1;
     587             :                 }
     588             :         }
     589             : 
     590           0 :         if (printblob) {
     591           0 :                 printf("%s\n", provision_text_data);
     592             :         }
     593             : 
     594           0 :         return 0;
     595             : }

Generated by: LCOV version 1.14