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

Generated by: LCOV version 1.14