"Fossies" - the Fresh Open Source Software Archive

Member "sssd-2.2.3/src/providers/ad/ad_gpo_child.c" (30 Nov 2019, 24331 Bytes) of package /linux/misc/sssd-2.2.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ad_gpo_child.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2     SSSD
    3 
    4     AD GPO Backend Module -- perform SMB and CSE processing in a child process
    5 
    6     Authors:
    7         Yassir Elley <yelley@redhat.com>
    8 
    9     Copyright (C) 2013 Red Hat
   10 
   11     This program is free software; you can redistribute it and/or modify
   12     it under the terms of the GNU General Public License as published by
   13     the Free Software Foundation; either version 3 of the License, or
   14     (at your option) any later version.
   15 
   16     This program is distributed in the hope that it will be useful,
   17     but WITHOUT ANY WARRANTY; without even the implied warranty of
   18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19     GNU General Public License for more details.
   20 
   21     You should have received a copy of the GNU General Public License
   22     along with this program.  If not, see <http://www.gnu.org/licenses/>.
   23 */
   24 
   25 #include <sys/types.h>
   26 #include <unistd.h>
   27 #include <sys/stat.h>
   28 #include <popt.h>
   29 #include <libsmbclient.h>
   30 #include <ini_configobj.h>
   31 #include <security/pam_modules.h>
   32 
   33 #include "util/util.h"
   34 #include "util/child_common.h"
   35 #include "providers/backend.h"
   36 #include "providers/ad/ad_gpo.h"
   37 #include "sss_cli.h"
   38 
   39 #define SMB_BUFFER_SIZE 65536
   40 #define GPT_INI "/GPT.INI"
   41 #define INI_GENERAL_SECTION "General"
   42 #define GPT_INI_VERSION "Version"
   43 
   44 struct input_buffer {
   45     int cached_gpt_version;
   46     const char *smb_server;
   47     const char *smb_share;
   48     const char *smb_path;
   49     const char *smb_cse_suffix;
   50 };
   51 
   52 static errno_t
   53 unpack_buffer(uint8_t *buf,
   54               size_t size,
   55               struct input_buffer *ibuf)
   56 {
   57     size_t p = 0;
   58     uint32_t len;
   59     uint32_t cached_gpt_version;
   60 
   61     /* cached_gpt_version */
   62     SAFEALIGN_COPY_UINT32_CHECK(&cached_gpt_version, buf + p, size, &p);
   63     DEBUG(SSSDBG_TRACE_FUNC, "cached_gpt_version: %d\n", cached_gpt_version);
   64     ibuf->cached_gpt_version = cached_gpt_version;
   65 
   66     /* smb_server */
   67     SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
   68     DEBUG(SSSDBG_TRACE_ALL, "smb_server length: %d\n", len);
   69     if (len == 0) {
   70         return EINVAL;
   71     } else {
   72         if (len > size - p) return EINVAL;
   73         ibuf->smb_server = talloc_strndup(ibuf, (char *)(buf + p), len);
   74         if (ibuf->smb_server == NULL) return ENOMEM;
   75         DEBUG(SSSDBG_TRACE_ALL, "smb_server: %s\n", ibuf->smb_server);
   76         p += len;
   77     }
   78 
   79     /* smb_share */
   80     SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
   81     DEBUG(SSSDBG_TRACE_ALL, "smb_share length: %d\n", len);
   82     if (len == 0) {
   83         return EINVAL;
   84     } else {
   85         if (len > size - p) return EINVAL;
   86         ibuf->smb_share = talloc_strndup(ibuf, (char *)(buf + p), len);
   87         if (ibuf->smb_share == NULL) return ENOMEM;
   88         DEBUG(SSSDBG_TRACE_ALL, "smb_share: %s\n", ibuf->smb_share);
   89         p += len;
   90     }
   91 
   92     /* smb_path */
   93     SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
   94     DEBUG(SSSDBG_TRACE_ALL, "smb_path length: %d\n", len);
   95     if (len == 0) {
   96         return EINVAL;
   97     } else {
   98         if (len > size - p) return EINVAL;
   99         ibuf->smb_path = talloc_strndup(ibuf, (char *)(buf + p), len);
  100         if (ibuf->smb_path == NULL) return ENOMEM;
  101         DEBUG(SSSDBG_TRACE_ALL, "smb_path: %s\n", ibuf->smb_path);
  102         p += len;
  103     }
  104 
  105     /* smb_cse_suffix */
  106     SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
  107     DEBUG(SSSDBG_TRACE_ALL, "smb_cse_suffix length: %d\n", len);
  108     if (len == 0) {
  109         return EINVAL;
  110     } else {
  111         if (len > size - p) return EINVAL;
  112         ibuf->smb_cse_suffix = talloc_strndup(ibuf, (char *)(buf + p), len);
  113         if (ibuf->smb_cse_suffix == NULL) return ENOMEM;
  114         DEBUG(SSSDBG_TRACE_ALL, "smb_cse_suffix: %s\n", ibuf->smb_cse_suffix);
  115         p += len;
  116     }
  117 
  118     return EOK;
  119 }
  120 
  121 
  122 static errno_t
  123 pack_buffer(struct response *r,
  124             int sysvol_gpt_version,
  125             int result)
  126 {
  127     size_t p = 0;
  128 
  129     /* A buffer with the following structure must be created:
  130      *   uint32_t sysvol_gpt_version (required)
  131      *   uint32_t status of the request (required)
  132      */
  133     r->size = 2 * sizeof(uint32_t);
  134 
  135     r->buf = talloc_array(r, uint8_t, r->size);
  136     if(r->buf == NULL) {
  137         return ENOMEM;
  138     }
  139 
  140     DEBUG(SSSDBG_TRACE_FUNC, "result [%d]\n", result);
  141 
  142     /* sysvol_gpt_version */
  143     SAFEALIGN_SET_UINT32(&r->buf[p], sysvol_gpt_version, &p);
  144 
  145     /* result */
  146     SAFEALIGN_SET_UINT32(&r->buf[p], result, &p);
  147 
  148     return EOK;
  149 }
  150 
  151 static errno_t
  152 prepare_response(TALLOC_CTX *mem_ctx,
  153                  int sysvol_gpt_version,
  154                  int result,
  155                  struct response **rsp)
  156 {
  157     int ret;
  158     struct response *r = NULL;
  159 
  160     r = talloc_zero(mem_ctx, struct response);
  161     if (r == NULL) {
  162         return ENOMEM;
  163     }
  164 
  165     r->buf = NULL;
  166     r->size = 0;
  167 
  168     ret = pack_buffer(r, sysvol_gpt_version, result);
  169     if (ret != EOK) {
  170         DEBUG(SSSDBG_CRIT_FAILURE, "pack_buffer failed\n");
  171         return ret;
  172     }
  173 
  174     *rsp = r;
  175     DEBUG(SSSDBG_TRACE_ALL, "r->size: %zu\n", r->size);
  176     return EOK;
  177 }
  178 
  179 static void
  180 sssd_krb_get_auth_data_fn(const char * pServer,
  181                           const char * pShare,
  182                           char * pWorkgroup,
  183                           int maxLenWorkgroup,
  184                           char * pUsername,
  185                           int maxLenUsername,
  186                           char * pPassword,
  187                           int maxLenPassword)
  188 {
  189     /* since we are using kerberos for authentication, we simply return */
  190     return;
  191 }
  192 
  193 /*
  194  * This function prepares the gpo_cache by:
  195  * - parsing the input_smb_path into its component directories
  196  * - creating each component directory (if it doesn't already exist)
  197  */
  198 static errno_t prepare_gpo_cache(TALLOC_CTX *mem_ctx,
  199                                  const char *cache_dir,
  200                                  const char *input_smb_path_with_suffix)
  201 {
  202     char *current_dir;
  203     char *ptr;
  204     const char delim = '/';
  205     int num_dirs = 0;
  206     int i;
  207     char *first = NULL;
  208     char *last = NULL;
  209     char *smb_path_with_suffix = NULL;
  210     errno_t ret;
  211     mode_t old_umask;
  212 
  213     smb_path_with_suffix = talloc_strdup(mem_ctx, input_smb_path_with_suffix);
  214     if (smb_path_with_suffix == NULL) {
  215         return ENOMEM;
  216     }
  217 
  218     DEBUG(SSSDBG_TRACE_ALL, "smb_path_with_suffix: %s\n", smb_path_with_suffix);
  219 
  220     current_dir = talloc_strdup(mem_ctx, cache_dir);
  221     if (current_dir == NULL) {
  222         return ENOMEM;
  223     }
  224 
  225     ptr = smb_path_with_suffix + 1;
  226     while ((ptr = strchr(ptr, delim))) {
  227         ptr++;
  228         num_dirs++;
  229     }
  230 
  231     ptr = smb_path_with_suffix + 1;
  232 
  233     old_umask = umask(SSS_DFL_X_UMASK);
  234     for (i = 0; i < num_dirs; i++) {
  235         first = ptr;
  236         last = strchr(first, delim);
  237         if (last == NULL) {
  238             ret = EINVAL;
  239             goto done;
  240         }
  241         *last = '\0';
  242         last++;
  243 
  244         current_dir = talloc_asprintf(mem_ctx, "%s/%s", current_dir, first);
  245         if (current_dir == NULL) {
  246             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
  247             ret = ENOMEM;
  248             goto done;
  249         }
  250         DEBUG(SSSDBG_TRACE_FUNC, "Storing GPOs in %s\n", current_dir);
  251 
  252         if ((mkdir(current_dir, 0700)) < 0 && errno != EEXIST) {
  253             ret = errno;
  254             DEBUG(SSSDBG_CRIT_FAILURE,
  255                   "mkdir(%s) failed: %d\n", current_dir, ret);
  256             goto done;
  257         }
  258 
  259         ptr = last;
  260     }
  261 
  262     ret = EOK;
  263 
  264 done:
  265     umask(old_umask);
  266 
  267     return ret;
  268 }
  269 
  270 /*
  271  * This function stores the input buf to a local file, whose file path
  272  * is constructed by concatenating:
  273  *   GPO_CACHE_PATH,
  274  *   input smb_path,
  275  *   input smb_cse_suffix
  276  * Note that the backend will later read the file from the same file path.
  277  */
  278 static errno_t gpo_cache_store_file(const char *smb_path,
  279                                     const char *smb_cse_suffix,
  280                                     uint8_t *buf,
  281                                     int buflen)
  282 {
  283     int ret;
  284     int fret;
  285     int fd = -1;
  286     char *tmp_name = NULL;
  287     ssize_t written;
  288     char *filename = NULL;
  289     char *smb_path_with_suffix = NULL;
  290     TALLOC_CTX *tmp_ctx = NULL;
  291 
  292     tmp_ctx = talloc_new(NULL);
  293     if (tmp_ctx == NULL) {
  294         ret = ENOMEM;
  295         goto done;
  296     }
  297 
  298     smb_path_with_suffix =
  299         talloc_asprintf(tmp_ctx, "%s%s", smb_path, smb_cse_suffix);
  300     if (smb_path_with_suffix == NULL) {
  301         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
  302         ret = ENOMEM;
  303         goto done;
  304     }
  305 
  306     /* create component directories of smb_path, if needed */
  307     ret = prepare_gpo_cache(tmp_ctx, GPO_CACHE_PATH, smb_path_with_suffix);
  308     if (ret != EOK) {
  309         DEBUG(SSSDBG_CRIT_FAILURE,
  310               "prepare_gpo_cache failed [%d][%s]\n",
  311               ret, strerror(ret));
  312         goto done;
  313     }
  314 
  315     filename = talloc_asprintf(tmp_ctx, GPO_CACHE_PATH"%s", smb_path_with_suffix);
  316     if (filename == NULL) {
  317         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
  318         ret = ENOMEM;
  319         goto done;
  320     }
  321 
  322     tmp_name = talloc_asprintf(tmp_ctx, "%sXXXXXX", filename);
  323     if (tmp_name == NULL) {
  324         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
  325         ret = ENOMEM;
  326         goto done;
  327     }
  328 
  329     fd = sss_unique_file(tmp_ctx, tmp_name, &ret);
  330     if (fd == -1) {
  331         DEBUG(SSSDBG_CRIT_FAILURE,
  332               "sss_unique_file failed [%d][%s].\n", ret, strerror(ret));
  333         goto done;
  334     }
  335 
  336     errno = 0;
  337     written = sss_atomic_write_s(fd, buf, buflen);
  338     if (written == -1) {
  339         ret = errno;
  340         DEBUG(SSSDBG_CRIT_FAILURE,
  341               "write failed [%d][%s].\n", ret, strerror(ret));
  342         goto done;
  343     }
  344 
  345     if (written != buflen) {
  346         DEBUG(SSSDBG_CRIT_FAILURE,
  347               "Write error, wrote [%zd] bytes, expected [%d]\n",
  348                written, buflen);
  349         ret = EIO;
  350         goto done;
  351     }
  352 
  353     ret = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
  354     if (ret == -1) {
  355         ret = errno;
  356         DEBUG(SSSDBG_CRIT_FAILURE,
  357               "fchmod failed [%d][%s].\n", ret, strerror(ret));
  358         goto done;
  359     }
  360 
  361     ret = rename(tmp_name, filename);
  362     if (ret == -1) {
  363         ret = errno;
  364         DEBUG(SSSDBG_CRIT_FAILURE,
  365               "rename failed [%d][%s].\n", ret, strerror(ret));
  366         goto done;
  367     }
  368 
  369     ret = EOK;
  370  done:
  371     if (ret != EOK) {
  372         DEBUG(SSSDBG_CRIT_FAILURE, "Error encountered: %d.\n", ret);
  373     }
  374 
  375     if (fd != -1) {
  376         fret = close(fd);
  377         if (fret == -1) {
  378             fret = errno;
  379             DEBUG(SSSDBG_CRIT_FAILURE,
  380                   "close failed [%d][%s].\n", fret, strerror(fret));
  381         }
  382     }
  383 
  384     talloc_free(tmp_ctx);
  385     return ret;
  386 }
  387 
  388 static errno_t
  389 parse_ini_file_with_libini(struct ini_cfgobj *ini_config,
  390                            int *_gpt_version)
  391 {
  392     int ret;
  393     struct value_obj *vobj = NULL;
  394     int gpt_version;
  395 
  396     ret = ini_get_config_valueobj(INI_GENERAL_SECTION, GPT_INI_VERSION,
  397                                   ini_config, INI_GET_FIRST_VALUE, &vobj);
  398     if (ret != 0) {
  399         DEBUG(SSSDBG_CRIT_FAILURE,
  400               "ini_get_config_valueobj failed [%d][%s]\n", ret, strerror(ret));
  401         goto done;
  402     }
  403     if (vobj == NULL) {
  404         DEBUG(SSSDBG_CRIT_FAILURE, "section/name not found: [%s][%s]\n",
  405               INI_GENERAL_SECTION, GPT_INI_VERSION);
  406         ret = EINVAL;
  407         goto done;
  408     }
  409 
  410     gpt_version = ini_get_int32_config_value(vobj, 0, -1, &ret);
  411     if (ret != 0) {
  412         DEBUG(SSSDBG_CRIT_FAILURE,
  413               "ini_get_int32_config_value failed [%d][%s]\n",
  414               ret, strerror(ret));
  415         goto done;
  416     }
  417 
  418     *_gpt_version = gpt_version;
  419 
  420     ret = EOK;
  421 
  422  done:
  423 
  424     return ret;
  425 }
  426 
  427 /*
  428  * This function parses the GPT_INI file stored in the gpo_cache, and uses the
  429  * results to populate the output parameters ...
  430  */
  431 static errno_t
  432 ad_gpo_parse_ini_file(const char *smb_path,
  433                       int *_gpt_version)
  434 {
  435     struct ini_cfgfile *file_ctx = NULL;
  436     struct ini_cfgobj *ini_config = NULL;
  437     const char *ini_filename;
  438     int ret;
  439     int gpt_version = -1;
  440     TALLOC_CTX *tmp_ctx = NULL;
  441 
  442     tmp_ctx = talloc_new(NULL);
  443     if (tmp_ctx == NULL) {
  444         ret = ENOMEM;
  445         goto done;
  446     }
  447 
  448     ini_filename = talloc_asprintf(tmp_ctx, GPO_CACHE_PATH"%s%s",
  449                                    smb_path, GPT_INI);
  450     if (ini_filename == NULL) {
  451         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
  452         ret = ENOMEM;
  453         goto done;
  454     }
  455 
  456     DEBUG(SSSDBG_TRACE_FUNC, "ini_filename:%s\n", ini_filename);
  457 
  458     ret = ini_config_create(&ini_config);
  459     if (ret != 0) {
  460         DEBUG(SSSDBG_CRIT_FAILURE,
  461               "ini_config_create failed [%d][%s]\n", ret, strerror(ret));
  462         goto done;
  463     }
  464 
  465     ret = ini_config_file_open(ini_filename, 0, &file_ctx);
  466     if (ret != 0) {
  467         DEBUG(SSSDBG_CRIT_FAILURE,
  468               "ini_config_file_open failed [%d][%s]\n", ret, strerror(ret));
  469         goto done;
  470     }
  471 
  472     ret = ini_config_parse(file_ctx, INI_STOP_ON_NONE, 0, 0, ini_config);
  473     if (ret != 0) {
  474         int lret;
  475         char **errors;
  476 
  477         DEBUG(SSSDBG_CRIT_FAILURE,
  478               "[%s]: ini_config_parse failed [%d][%s]\n",
  479               ini_filename, ret, strerror(ret));
  480 
  481         /* Now get specific errors if there are any */
  482         lret = ini_config_get_errors(ini_config, &errors);
  483         if (lret != 0) {
  484             DEBUG(SSSDBG_CRIT_FAILURE,
  485                   "Failed to get specific parse error [%d][%s]\n", lret,
  486                   strerror(lret));
  487             goto done;
  488         }
  489 
  490         for (int i = 0; errors[i]; i++) {
  491              DEBUG(SSSDBG_CRIT_FAILURE, "%s\n", errors[i]);
  492         }
  493         ini_config_free_errors(errors);
  494 
  495         goto done;
  496     }
  497 
  498     ret = parse_ini_file_with_libini(ini_config, &gpt_version);
  499     if (ret != 0) {
  500         DEBUG(SSSDBG_CRIT_FAILURE,
  501               "parse_ini_file_with_libini failed [%d][%s]\n",
  502               ret, strerror(ret));
  503         goto done;
  504     }
  505 
  506     *_gpt_version = gpt_version;
  507 
  508  done:
  509 
  510     if (ret != EOK) {
  511         DEBUG(SSSDBG_CRIT_FAILURE, "Error encountered: %d.\n", ret);
  512     }
  513 
  514     ini_config_file_destroy(file_ctx);
  515     ini_config_destroy(ini_config);
  516     talloc_free(tmp_ctx);
  517     return ret;
  518 }
  519 
  520 /*
  521  * This function uses the input smb uri components to download a sysvol file
  522  * (e.g. INI file, policy file, etc) and store it to the GPO_CACHE directory.
  523  */
  524 static errno_t
  525 copy_smb_file_to_gpo_cache(SMBCCTX *smbc_ctx,
  526                            const char *smb_server,
  527                            const char *smb_share,
  528                            const char *smb_path,
  529                            const char *smb_cse_suffix)
  530 {
  531     char *smb_uri = NULL;
  532     SMBCFILE *file;
  533     int ret;
  534     uint8_t *buf = NULL;
  535     int buflen = 0;
  536 
  537     TALLOC_CTX *tmp_ctx = NULL;
  538 
  539     tmp_ctx = talloc_new(NULL);
  540     if (tmp_ctx == NULL) {
  541         return ENOMEM;
  542     }
  543 
  544     smb_uri = talloc_asprintf(tmp_ctx, "%s%s%s%s", smb_server,
  545                               smb_share, smb_path, smb_cse_suffix);
  546     if (smb_uri == NULL) {
  547         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
  548         ret = ENOMEM;
  549         goto done;
  550     }
  551 
  552     DEBUG(SSSDBG_TRACE_FUNC, "smb_uri: %s\n", smb_uri);
  553 
  554     errno = 0;
  555     file = smbc_getFunctionOpen(smbc_ctx)(smbc_ctx, smb_uri, O_RDONLY, 0755);
  556     if (file == NULL) {
  557         ret = errno;
  558         DEBUG(SSSDBG_CRIT_FAILURE, "smbc_getFunctionOpen failed [%d][%s]\n",
  559               ret, strerror(ret));
  560         goto done;
  561     }
  562 
  563     buf = talloc_array(tmp_ctx, uint8_t, SMB_BUFFER_SIZE);
  564     if (buf == NULL) {
  565         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n");
  566         ret = ENOMEM;
  567         goto done;
  568     }
  569 
  570     errno = 0;
  571     buflen = smbc_getFunctionRead(smbc_ctx)(smbc_ctx, file, buf, SMB_BUFFER_SIZE);
  572     if (buflen < 0) {
  573         ret = errno;
  574         DEBUG(SSSDBG_CRIT_FAILURE, "smbc_getFunctionRead failed [%d][%s]\n",
  575               ret, strerror(ret));
  576         goto done;
  577     }
  578 
  579     DEBUG(SSSDBG_TRACE_ALL, "smb_buflen: %d\n", buflen);
  580 
  581     ret = gpo_cache_store_file(smb_path, smb_cse_suffix, buf, buflen);
  582     if (ret != EOK) {
  583         DEBUG(SSSDBG_CRIT_FAILURE,
  584               "gpo_cache_store_file failed [%d][%s]\n",
  585               ret, strerror(ret));
  586         goto done;
  587     }
  588 
  589  done:
  590     talloc_free(tmp_ctx);
  591     return ret;
  592 }
  593 
  594 
  595 /*
  596  * Using its smb_uri components and cached_gpt_version inputs, this function
  597  * does several things:
  598  * - it downloads the GPT_INI file to GPO_CACHE
  599  * - it parses the sysvol_gpt_version field from the GPT_INI file
  600  * - if the sysvol_gpt_version is greater than the cached_gpt_version
  601  *   - it downloads the policy file to GPO_CACHE
  602  * - else
  603  *   - it doesn't retrieve the policy file
  604  *   - in this case, the backend will use the existing policy file in GPO_CACHE
  605  * - it returns the sysvol_gpt_version in the _sysvol_gpt_version output param
  606  *
  607  * Note that if the cached_gpt_version sent by the backend is -1 (to indicate
  608  * that no gpt_version has been set in the cache for the corresponding gpo_guid),
  609  * then the parsed sysvol_gpt_version (which must be at least 0) will be greater
  610  * than the cached_gpt_version, thereby triggering a fresh download.
  611  *
  612  * Note that the backend will later do the following:
  613  * - backend will save the sysvol_gpt_version to sysdb cache
  614  * - backend will read the policy file from the GPO_CACHE
  615  */
  616 static errno_t
  617 perform_smb_operations(int cached_gpt_version,
  618                        const char *smb_server,
  619                        const char *smb_share,
  620                        const char *smb_path,
  621                        const char *smb_cse_suffix,
  622                        int *_sysvol_gpt_version)
  623 {
  624     SMBCCTX *smbc_ctx;
  625     int ret;
  626     int sysvol_gpt_version;
  627 
  628     smbc_ctx = smbc_new_context();
  629     if (smbc_ctx == NULL) {
  630         DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate new smbc context\n");
  631         ret = ENOMEM;
  632         goto done;
  633     }
  634 
  635     smbc_setOptionDebugToStderr(smbc_ctx, 1);
  636     smbc_setFunctionAuthData(smbc_ctx, sssd_krb_get_auth_data_fn);
  637     smbc_setOptionUseKerberos(smbc_ctx, 1);
  638 
  639     /* Initialize the context using the previously specified options */
  640     if (smbc_init_context(smbc_ctx) == NULL) {
  641         DEBUG(SSSDBG_CRIT_FAILURE, "Could not initialize smbc context\n");
  642         ret = ENOMEM;
  643         goto done;
  644     }
  645 
  646     /* download ini file */
  647     ret = copy_smb_file_to_gpo_cache(smbc_ctx, smb_server, smb_share, smb_path,
  648                                      GPT_INI);
  649     if (ret != EOK) {
  650         DEBUG(SSSDBG_CRIT_FAILURE,
  651               "copy_smb_file_to_gpo_cache failed [%d][%s]\n",
  652               ret, strerror(ret));
  653         goto done;
  654     }
  655 
  656     ret = ad_gpo_parse_ini_file(smb_path, &sysvol_gpt_version);
  657     if (ret != EOK) {
  658         DEBUG(SSSDBG_CRIT_FAILURE,
  659               "Cannot parse ini file: [%d][%s]\n", ret, strerror(ret));
  660         goto done;
  661     }
  662 
  663     DEBUG(SSSDBG_TRACE_FUNC, "sysvol_gpt_version: %d\n", sysvol_gpt_version);
  664 
  665     if (sysvol_gpt_version > cached_gpt_version) {
  666         /* download policy file */
  667         ret = copy_smb_file_to_gpo_cache(smbc_ctx, smb_server, smb_share,
  668                                          smb_path, smb_cse_suffix);
  669         if (ret != EOK) {
  670             DEBUG(SSSDBG_CRIT_FAILURE,
  671                   "copy_smb_file_to_gpo_cache failed [%d][%s]\n",
  672                   ret, strerror(ret));
  673             goto done;
  674         }
  675     }
  676 
  677     *_sysvol_gpt_version = sysvol_gpt_version;
  678 
  679  done:
  680     smbc_free_context(smbc_ctx, 0);
  681     return ret;
  682 }
  683 
  684 int
  685 main(int argc, const char *argv[])
  686 {
  687     int opt;
  688     poptContext pc;
  689     int debug_fd = -1;
  690     const char *opt_logger = NULL;
  691     errno_t ret;
  692     int sysvol_gpt_version;
  693     int result;
  694     TALLOC_CTX *main_ctx = NULL;
  695     uint8_t *buf = NULL;
  696     ssize_t len = 0;
  697     struct input_buffer *ibuf = NULL;
  698     struct response *resp = NULL;
  699     ssize_t written;
  700 
  701     struct poptOption long_options[] = {
  702         POPT_AUTOHELP
  703         {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0,
  704          _("Debug level"), NULL},
  705         {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0,
  706          _("Add debug timestamps"), NULL},
  707         {"debug-microseconds", 0, POPT_ARG_INT, &debug_microseconds, 0,
  708          _("Show timestamps with microseconds"), NULL},
  709         {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0,
  710          _("An open file descriptor for the debug logs"), NULL},
  711         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN,
  712          &debug_to_stderr, 0,
  713          _("Send the debug output to stderr directly."), NULL },
  714         SSSD_LOGGER_OPTS
  715         POPT_TABLEEND
  716     };
  717 
  718     /* Set debug level to invalid value so we can decide if -d 0 was used. */
  719     debug_level = SSSDBG_INVALID;
  720 
  721     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
  722     while((opt = poptGetNextOpt(pc)) != -1) {
  723         switch(opt) {
  724         default:
  725         fprintf(stderr, "\nInvalid option %s: %s\n\n",
  726                   poptBadOption(pc, 0), poptStrerror(opt));
  727             poptPrintUsage(pc, stderr, 0);
  728             _exit(-1);
  729         }
  730     }
  731 
  732     poptFreeContext(pc);
  733 
  734     DEBUG_INIT(debug_level);
  735 
  736     debug_prg_name = talloc_asprintf(NULL, "[sssd[gpo_child[%d]]]", getpid());
  737     if (debug_prg_name == NULL) {
  738         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
  739         goto fail;
  740     }
  741 
  742     if (debug_fd != -1) {
  743         ret = set_debug_file_from_fd(debug_fd);
  744         if (ret != EOK) {
  745             DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
  746         }
  747         opt_logger = sss_logger_str[FILES_LOGGER];
  748     }
  749 
  750     sss_set_logger(opt_logger);
  751 
  752     DEBUG(SSSDBG_TRACE_FUNC, "gpo_child started.\n");
  753 
  754     main_ctx = talloc_new(NULL);
  755     if (main_ctx == NULL) {
  756         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
  757         talloc_free(discard_const(debug_prg_name));
  758         goto fail;
  759     }
  760     talloc_steal(main_ctx, debug_prg_name);
  761 
  762     buf = talloc_size(main_ctx, sizeof(uint8_t)*IN_BUF_SIZE);
  763     if (buf == NULL) {
  764         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
  765         goto fail;
  766     }
  767 
  768     ibuf = talloc_zero(main_ctx, struct input_buffer);
  769     if (ibuf == NULL) {
  770         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
  771         goto fail;
  772     }
  773 
  774     DEBUG(SSSDBG_TRACE_FUNC, "context initialized\n");
  775 
  776     errno = 0;
  777     len = sss_atomic_read_s(STDIN_FILENO, buf, IN_BUF_SIZE);
  778     if (len == -1) {
  779         ret = errno;
  780         DEBUG(SSSDBG_CRIT_FAILURE, "read failed [%d][%s].\n", ret, strerror(ret));
  781         goto fail;
  782     }
  783 
  784     close(STDIN_FILENO);
  785 
  786     ret = unpack_buffer(buf, len, ibuf);
  787     if (ret != EOK) {
  788         DEBUG(SSSDBG_CRIT_FAILURE,
  789               "unpack_buffer failed.[%d][%s].\n", ret, strerror(ret));
  790         goto fail;
  791     }
  792 
  793     DEBUG(SSSDBG_TRACE_FUNC, "performing smb operations\n");
  794 
  795     result = perform_smb_operations(ibuf->cached_gpt_version,
  796                                     ibuf->smb_server,
  797                                     ibuf->smb_share,
  798                                     ibuf->smb_path,
  799                                     ibuf->smb_cse_suffix,
  800                                     &sysvol_gpt_version);
  801     if (result != EOK) {
  802         DEBUG(SSSDBG_CRIT_FAILURE,
  803               "perform_smb_operations failed.[%d][%s].\n",
  804               result, strerror(result));
  805         goto fail;
  806     }
  807 
  808     ret = prepare_response(main_ctx, sysvol_gpt_version, result, &resp);
  809     if (ret != EOK) {
  810         DEBUG(SSSDBG_CRIT_FAILURE, "prepare_response failed. [%d][%s].\n",
  811                     ret, strerror(ret));
  812         goto fail;
  813     }
  814 
  815     errno = 0;
  816 
  817     written = sss_atomic_write_s(AD_GPO_CHILD_OUT_FILENO, resp->buf, resp->size);
  818     if (written == -1) {
  819         ret = errno;
  820         DEBUG(SSSDBG_CRIT_FAILURE, "write failed [%d][%s].\n", ret,
  821                     strerror(ret));
  822         goto fail;
  823     }
  824 
  825     if (written != resp->size) {
  826         DEBUG(SSSDBG_CRIT_FAILURE, "Expected to write %zu bytes, wrote %zu\n",
  827               resp->size, written);
  828         goto fail;
  829     }
  830 
  831     DEBUG(SSSDBG_TRACE_FUNC, "gpo_child completed successfully\n");
  832     close(AD_GPO_CHILD_OUT_FILENO);
  833     talloc_free(main_ctx);
  834     return EXIT_SUCCESS;
  835 
  836 fail:
  837     DEBUG(SSSDBG_CRIT_FAILURE, "gpo_child failed!\n");
  838     close(AD_GPO_CHILD_OUT_FILENO);
  839     talloc_free(main_ctx);
  840     return EXIT_FAILURE;
  841 }