LCOV - code coverage report
Current view: top level - source3/utils - net_offlinejoin.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 161 323 49.8 %
Date: 2024-02-28 12:06:22 Functions: 4 8 50.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          36 : int net_offlinejoin(struct net_context *c, int argc, const char **argv)
      41             : {
      42           0 :         int ret;
      43           0 :         NET_API_STATUS status;
      44             : 
      45          36 :         if ((argc > 0) && (strcasecmp_m(argv[0], "HELP") == 0)) {
      46           0 :                 net_offlinejoin_usage(c, argc, argv);
      47           0 :                 return 0;
      48             :         }
      49             : 
      50          36 :         if (argc == 0) {
      51           0 :                 net_offlinejoin_usage(c, argc, argv);
      52           0 :                 return -1;
      53             :         }
      54             : 
      55          36 :         net_warn_member_options();
      56             : 
      57          36 :         status = libnetapi_net_init(&c->netapi_ctx, c->lp_ctx, c->creds);
      58          36 :         if (status != 0) {
      59           0 :                 return -1;
      60             :         }
      61             : 
      62          36 :         if (c->opt_kerberos) {
      63           0 :                 libnetapi_set_use_kerberos(c->netapi_ctx);
      64             :         }
      65             : 
      66          36 :         if (strcasecmp_m(argv[0], "provision") == 0) {
      67          12 :                 ret = net_offlinejoin_provision(c, argc, argv);
      68          12 :                 if (ret != 0) {
      69           0 :                         return ret;
      70             :                 }
      71             :         }
      72             : 
      73          36 :         if (strcasecmp_m(argv[0], "requestodj") == 0) {
      74          18 :                 ret = net_offlinejoin_requestodj(c, argc, argv);
      75          18 :                 if (ret != 0) {
      76           0 :                         return ret;
      77             :                 }
      78             :         }
      79             : 
      80          36 :         if (strcasecmp_m(argv[0], "composeodj") == 0) {
      81           6 :                 ret = net_offlinejoin_composeodj(c, argc, argv);
      82           6 :                 if (ret != 0) {
      83           0 :                         return ret;
      84             :                 }
      85             :         }
      86             : 
      87          36 :         return 0;
      88             : }
      89             : 
      90           0 : static int net_offlinejoin_provision_usage(struct net_context *c, int argc, const char **argv)
      91             : {
      92           0 :         d_printf(_("\nnet offlinejoin provision [misc. options]\n"
      93             :                    "\tProvisions machine account in AD\n"));
      94           0 :         d_printf(_("Valid options:\n"));
      95           0 :         d_printf(_("\tdomain=<DOMAIN>\t\t\t\tDefines AD Domain to join\n"));
      96           0 :         d_printf(_("\tmachine_name=<MACHINE_NAME>\t\tDefines the machine account name\n"));
      97           0 :         d_printf(_("\tmachine_account_ou=<OU>\t\t\tDefines the machine account organizational unit DN\n"));
      98           0 :         d_printf(_("\tdcname=<DCNAME>\t\t\t\tSpecify a Domain Controller to join to\n"));
      99           0 :         d_printf(_("\tdefpwd\t\t\t\t\tUse default machine account password\n"));
     100           0 :         d_printf(_("\treuse\t\t\t\t\tReuse existing machine account in AD\n"));
     101           0 :         d_printf(_("\tsavefile=<FILENAME>\t\t\tFile to store the ODJ data\n"));
     102           0 :         d_printf(_("\tprintblob\t\t\t\tPrint the base64 encoded ODJ data on stdout\n"));
     103           0 :         net_common_flags_usage(c, argc, argv);
     104           0 :         return -1;
     105             : }
     106             : 
     107          12 : int net_offlinejoin_provision(struct net_context *c,
     108             :                               int argc, const char **argv)
     109             : {
     110           0 :         NET_API_STATUS status;
     111          12 :         const char *dcname = NULL;
     112          12 :         const char *domain = NULL;
     113          12 :         const char *machine_name = NULL;
     114          12 :         const char *machine_account_ou = NULL;
     115          12 :         const char *provision_text_data = NULL;
     116          12 :         uint32_t options = 0;
     117          12 :         const char *savefile = NULL;
     118          12 :         bool printblob = false;
     119           0 :         int i;
     120             : 
     121          12 :         if (c->display_usage || argc == 1) {
     122           0 :                 return net_offlinejoin_provision_usage(c, argc, argv);
     123             :         }
     124             : 
     125             :         /* process additional command line args */
     126             : 
     127          70 :         for (i = 0; i < argc; i++) {
     128             : 
     129          58 :                 if (strnequal(argv[i], "domain", strlen("domain"))) {
     130          12 :                         domain = get_string_param(argv[i]);
     131          12 :                         if (domain == NULL) {
     132           0 :                                 return -1;
     133             :                         }
     134             :                 }
     135          58 :                 if (strnequal(argv[i], "machine_name", strlen("machine_name"))) {
     136          12 :                         machine_name = get_string_param(argv[i]);
     137          12 :                         if (machine_name == NULL) {
     138           0 :                                 return -1;
     139             :                         }
     140             :                 }
     141          58 :                 if (strnequal(argv[i], "machine_account_ou", strlen("machine_account_ou"))) {
     142           0 :                         machine_account_ou = get_string_param(argv[i]);
     143           0 :                         if (machine_account_ou == NULL) {
     144           0 :                                 return -1;
     145             :                         }
     146             :                 }
     147          58 :                 if (strnequal(argv[i], "dcname", strlen("dcname"))) {
     148           4 :                         dcname = get_string_param(argv[i]);
     149           4 :                         if (dcname == NULL) {
     150           0 :                                 return -1;
     151             :                         }
     152             :                 }
     153          58 :                 if (strnequal(argv[i], "defpwd", strlen("defpwd"))) {
     154           6 :                         options |= NETSETUP_PROVISION_USE_DEFAULT_PASSWORD;
     155             :                 }
     156          58 :                 if (strnequal(argv[i], "reuse", strlen("reuse"))) {
     157           0 :                         options |= NETSETUP_PROVISION_REUSE_ACCOUNT;
     158             :                 }
     159          58 :                 if (strnequal(argv[i], "savefile", strlen("savefile"))) {
     160          12 :                         savefile = get_string_param(argv[i]);
     161          12 :                         if (savefile == NULL) {
     162           0 :                                 return -1;
     163             :                         }
     164             :                 }
     165          58 :                 if (strnequal(argv[i], "printblob", strlen("printblob"))) {
     166           0 :                         printblob = true;
     167             :                 }
     168             :         }
     169             : 
     170          12 :         if (domain == NULL) {
     171           0 :                 d_printf("Failed to provision computer account: %s\n",
     172           0 :                          libnetapi_errstr(W_ERROR_V(WERR_INVALID_DOMAINNAME)));
     173           0 :                 return -1;
     174             :         }
     175             : 
     176          12 :         if (machine_name == NULL) {
     177           0 :                 d_printf("Failed to provision computer account: %s\n",
     178           0 :                          libnetapi_errstr(W_ERROR_V(WERR_INVALID_COMPUTERNAME)));
     179           0 :                 return -1;
     180             :         }
     181             : 
     182          12 :         status = NetProvisionComputerAccount(domain,
     183             :                                              machine_name,
     184             :                                              machine_account_ou,
     185             :                                              dcname,
     186             :                                              options,
     187             :                                              NULL,
     188             :                                              0,
     189             :                                              &provision_text_data);
     190          12 :         if (status != 0) {
     191           0 :                 d_printf("Failed to provision computer account: %s\n",
     192             :                         libnetapi_get_error_string(c->netapi_ctx, status));
     193           0 :                 return status;
     194             :         }
     195             : 
     196          12 :         if (savefile != NULL) {
     197             : 
     198           0 :                 DATA_BLOB ucs2_blob, blob;
     199           0 :                 bool ok;
     200             : 
     201             :                 /*
     202             :                  * Windows produces and consumes UTF16/UCS2 encoded blobs
     203             :                  * so we also do it for compatibility. Someone may provision an
     204             :                  * account for a Windows machine with samba.
     205             :                  */
     206          12 :                 ok = push_reg_sz(c, &ucs2_blob, provision_text_data);
     207          12 :                 if (!ok) {
     208           0 :                         return -1;
     209             :                 }
     210             : 
     211             :                 /* Add the unicode BOM mark */
     212          12 :                 blob = data_blob_talloc(c, NULL, ucs2_blob.length + 2);
     213          12 :                 if (blob.data == NULL) {
     214           0 :                         d_printf("Failed to allocate blob: %s\n",
     215           0 :                                  strerror(errno));
     216           0 :                         return -1;
     217             :                 }
     218             : 
     219          12 :                 blob.data[0] = 0xff;
     220          12 :                 blob.data[1] = 0xfe;
     221             : 
     222          12 :                 memcpy(blob.data + 2, ucs2_blob.data, ucs2_blob.length);
     223             : 
     224          12 :                 ok = file_save(savefile, blob.data, blob.length);
     225          12 :                 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          12 :         d_printf("Successfully provisioned computer '%s' in domain '%s'\n",
     233             :                         machine_name, domain);
     234             : 
     235          12 :         if (printblob) {
     236           0 :                 printf("%s\n", provision_text_data);
     237             :         }
     238             : 
     239          12 :         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          18 : int net_offlinejoin_requestodj(struct net_context *c,
     255             :                                int argc, const char **argv)
     256             : {
     257           0 :         NET_API_STATUS status;
     258          18 :         uint8_t *provision_bin_data = NULL;
     259          18 :         size_t provision_bin_data_size = 0;
     260          18 :         uint32_t options = NETSETUP_PROVISION_ONLINE_CALLER;
     261          18 :         const char *windows_path = NULL;
     262           0 :         int i;
     263             : 
     264          18 :         if (c->display_usage) {
     265           0 :                 return net_offlinejoin_requestodj_usage(c, argc, argv);
     266             :         }
     267             : 
     268             :         /* process additional command line args */
     269             : 
     270          54 :         for (i = 0; i < argc; i++) {
     271             : 
     272          36 :                 if (strnequal(argv[i], "loadfile", strlen("loadfile"))) {
     273          18 :                         const char *loadfile = NULL;
     274             : 
     275          18 :                         loadfile = get_string_param(argv[i]);
     276          18 :                         if (loadfile == NULL) {
     277           0 :                                 return -1;
     278             :                         }
     279             : 
     280           0 :                         provision_bin_data =
     281          18 :                                 (uint8_t *)file_load(loadfile,
     282             :                                                      &provision_bin_data_size,
     283             :                                                      0,
     284             :                                                      c);
     285          18 :                         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          18 :         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           0 :                 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          18 :         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) or from stdin (-i)\n");
     321           0 :                 return -1;
     322             :         }
     323          18 :         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          18 :         status = NetRequestOfflineDomainJoin(provision_bin_data,
     330             :                                              provision_bin_data_size,
     331             :                                              options,
     332             :                                              windows_path);
     333          18 :         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          18 :         d_printf("Successfully requested Offline Domain Join\n");
     341             : 
     342          18 :         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           6 : int net_offlinejoin_composeodj(struct net_context *c,
     368             :                                int argc,
     369             :                                const char **argv)
     370             : {
     371           6 :         struct cli_credentials *creds = samba_cmdline_get_creds();
     372           0 :         NET_API_STATUS status;
     373           6 :         const char *dns_domain_name = NULL;
     374           6 :         const char *netbios_domain_name = NULL;
     375           6 :         const char *machine_account_name = NULL;
     376           6 :         const char *machine_account_password = NULL;
     377           6 :         const char *domain_sid_str = NULL;
     378           6 :         const char *domain_guid_str = NULL;
     379           0 :         struct dom_sid domain_sid;
     380           0 :         struct GUID domain_guid;
     381           6 :         const char *forest_name = NULL;
     382           6 :         const char *dc_name = NULL;
     383           6 :         char dc_address[INET6_ADDRSTRLEN] = { 0 };
     384           6 :         bool domain_is_ad = true;
     385           6 :         const char *provision_text_data = NULL;
     386           6 :         const char *savefile = NULL;
     387           6 :         bool printblob = false;
     388           0 :         enum credentials_obtained obtained;
     389           0 :         bool ok;
     390           0 :         NTSTATUS ntstatus;
     391           0 :         int i;
     392             : 
     393           6 :         if (c->display_usage || argc < 4) {
     394           0 :                 return net_offlinejoin_composeodj_usage(c, argc, argv);
     395             :         }
     396             : 
     397           6 :         dns_domain_name = cli_credentials_get_realm(creds);
     398           6 :         netbios_domain_name = cli_credentials_get_domain(creds);
     399             : 
     400           6 :         machine_account_name = cli_credentials_get_username_and_obtained(creds, &obtained);
     401           6 :         if (obtained < CRED_CALLBACK_RESULT) {
     402           2 :                 const char *netbios_name = cli_credentials_get_workstation(creds);
     403           2 :                 cli_credentials_set_username(
     404             :                         creds,
     405           2 :                         talloc_asprintf(c, "%s$", netbios_name),
     406             :                         CRED_SPECIFIED);
     407             :         }
     408             : 
     409           6 :         machine_account_name = cli_credentials_get_username(creds);
     410           6 :         machine_account_password = cli_credentials_get_password(creds);
     411           6 :         dc_name = c->opt_host;
     412             : 
     413           6 :         if (c->opt_have_ip) {
     414           6 :                 struct sockaddr_in *in4 = NULL;
     415           6 :                 struct sockaddr_in6 *in6 = NULL;
     416           6 :                 const char *p = NULL;
     417             : 
     418           6 :                 switch(c->opt_dest_ip.ss_family) {
     419           6 :                 case AF_INET:
     420           6 :                         in4 = (struct sockaddr_in *)&c->opt_dest_ip;
     421           6 :                         p = inet_ntop(AF_INET, &in4->sin_addr, dc_address, sizeof(dc_address));
     422           6 :                         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           6 :                 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          36 :         for (i = 0; i < argc; i++) {
     441          30 :                 if (strnequal(argv[i], "domain_sid", strlen("domain_sid"))) {
     442           6 :                         domain_sid_str = get_string_param(argv[i]);
     443           6 :                         if (domain_sid_str == NULL) {
     444           0 :                                 return -1;
     445             :                         }
     446             :                 }
     447             : 
     448          30 :                 if (strnequal(argv[i], "domain_guid", strlen("domain_guid"))) {
     449           6 :                         domain_guid_str = get_string_param(argv[i]);
     450           6 :                         if (domain_guid_str == NULL) {
     451           0 :                                 return -1;
     452             :                         }
     453             :                 }
     454             : 
     455          30 :                 if (strnequal(argv[i], "forest_name", strlen("forest_name"))) {
     456           6 :                         forest_name = get_string_param(argv[i]);
     457           6 :                         if (forest_name == NULL) {
     458           0 :                                 return -1;
     459             :                         }
     460             :                 }
     461             : 
     462          30 :                 if (strnequal(argv[i], "savefile", strlen("savefile"))) {
     463           6 :                         savefile = get_string_param(argv[i]);
     464           6 :                         if (savefile == NULL) {
     465           0 :                                 return -1;
     466             :                         }
     467             :                 }
     468             : 
     469          30 :                 if (strnequal(argv[i], "printblob", strlen("printblob"))) {
     470           0 :                         printblob = true;
     471             :                 }
     472             : 
     473          30 :                 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           6 :         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           6 :         if (dns_domain_name == NULL) {
     486           0 :                 d_printf("Please provide a valid realm parameter (--realm)\n");
     487           0 :                 return -1;
     488             :         }
     489             : 
     490           6 :         if (netbios_domain_name == NULL) {
     491           0 :                 d_printf("Please provide a valid domain parameter (--workgroup)\n");
     492           0 :                 return -1;
     493             :         }
     494             : 
     495           6 :         if (dc_name == NULL) {
     496           0 :                 d_printf("Please provide a valid DC name parameter (-S)\n");
     497           0 :                 return -1;
     498             :         }
     499             : 
     500           6 :         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           6 :         if (machine_account_name == NULL) {
     506           0 :                 d_printf("Please provide a valid netbios name parameter\n");
     507           0 :                 return -1;
     508             :         }
     509             : 
     510           6 :         if (machine_account_password == NULL) {
     511           0 :                 d_printf("Please provide a valid password parameter\n");
     512           0 :                 return -1;
     513             :         }
     514             : 
     515           6 :         if (domain_sid_str == NULL) {
     516           0 :                 d_printf("Please provide a valid <domain_sid> parameter\n");
     517           0 :                 return -1;
     518             :         }
     519             : 
     520           6 :         if (domain_guid_str == NULL) {
     521           0 :                 d_printf("Please provide a valid <domain_guid> parameter\n");
     522           0 :                 return -1;
     523             :         }
     524             : 
     525           6 :         if (forest_name == NULL) {
     526           0 :                 d_printf("Please provide a valid <forest_name> parameter\n");
     527           0 :                 return -1;
     528             :         }
     529             : 
     530           6 :         ok = dom_sid_parse(domain_sid_str, &domain_sid);
     531           6 :         if (!ok) {
     532           0 :                 d_fprintf(stderr, _("Failed to parse domain SID\n"));
     533           0 :                 return -1;
     534             :         }
     535             : 
     536           6 :         ntstatus = GUID_from_string(domain_guid_str, &domain_guid);
     537           6 :         if (NT_STATUS_IS_ERR(ntstatus)) {
     538           0 :                 d_fprintf(stderr, _("Failed to parse domain GUID\n"));
     539           0 :                 return -1;
     540             :         }
     541             : 
     542           6 :         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           6 :         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           6 :         if (savefile != NULL) {
     562           0 :                 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           6 :                 ok = push_reg_sz(c, &ucs2_blob, provision_text_data);
     570           6 :                 if (!ok) {
     571           0 :                         return -1;
     572             :                 }
     573             : 
     574             :                 /* Add the unicode BOM mark */
     575           6 :                 blob = data_blob_talloc(c, NULL, ucs2_blob.length + 2);
     576           6 :                 if (blob.data == NULL) {
     577           0 :                         d_printf("Failed to allocate blob: %s\n",
     578           0 :                                  strerror(errno));
     579           0 :                         return -1;
     580             :                 }
     581             : 
     582           6 :                 blob.data[0] = 0xff;
     583           6 :                 blob.data[1] = 0xfe;
     584             : 
     585           6 :                 memcpy(blob.data + 2, ucs2_blob.data, ucs2_blob.length);
     586             : 
     587           6 :                 ok = file_save(savefile, blob.data, blob.length);
     588           6 :                 if (!ok) {
     589           0 :                         d_printf("Failed to save %s: %s\n", savefile,
     590           0 :                                         strerror(errno));
     591           0 :                         return -1;
     592             :                 }
     593             :         }
     594             : 
     595           6 :         if (printblob) {
     596           0 :                 printf("%s\n", provision_text_data);
     597             :         }
     598             : 
     599           6 :         return 0;
     600             : }

Generated by: LCOV version 1.14