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

Generated by: LCOV version 1.14