LCOV - code coverage report
Current view: top level - tools - sss_seed.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 485 0.0 %
Date: 2015-10-19 Functions: 0 11 0.0 %

          Line data    Source code
       1             : #include <stdio.h>
       2             : #include <stdlib.h>
       3             : #include <string.h>
       4             : #include <talloc.h>
       5             : #include <popt.h>
       6             : #include <errno.h>
       7             : #include <unistd.h>
       8             : #include <limits.h>
       9             : #include <grp.h>
      10             : #include <pwd.h>
      11             : #include <sys/types.h>
      12             : #include <sys/stat.h>
      13             : #include <fcntl.h>
      14             : #include <ctype.h>
      15             : 
      16             : #include "util/util.h"
      17             : #include "db/sysdb.h"
      18             : #include "tools/tools_util.h"
      19             : #include "tools/sss_sync_ops.h"
      20             : #include "confdb/confdb.h"
      21             : 
      22             : #ifndef BUFSIZE
      23             : #define BUFSIZE 1024
      24             : #endif
      25             : 
      26             : #ifndef PASS_MAX
      27             : #define PASS_MAX 64
      28             : #endif
      29             : 
      30             : enum seed_pass_method {
      31             :     PASS_PROMPT,
      32             :     PASS_FILE
      33             : };
      34             : 
      35             : struct user_ctx {
      36             :     char *domain_name;
      37             : 
      38             :     char *name;
      39             :     uid_t uid;
      40             :     gid_t gid;
      41             :     char *gecos;
      42             :     char *home;
      43             :     char *shell;
      44             : 
      45             :     char *password;
      46             : };
      47             : 
      48             : struct seed_ctx {
      49             :     struct confdb_ctx *confdb;
      50             :     struct sss_domain_info *domain;
      51             :     struct sysdb_ctx *sysdb;
      52             : 
      53             :     struct user_ctx *uctx;
      54             : 
      55             :     char *password_file;
      56             :     enum seed_pass_method password_method;
      57             : 
      58             :     bool interact;
      59             :     bool user_cached;
      60             : };
      61             : 
      62             : 
      63           0 : static int seed_prompt(const char *req)
      64             : {
      65           0 :     ssize_t len = 0;
      66           0 :     size_t i = 0;
      67           0 :     char *prompt = NULL;
      68           0 :     int ret = EOK;
      69             : 
      70           0 :     prompt = talloc_asprintf(NULL, _("Enter %s:"), req);
      71           0 :     if (prompt == NULL) {
      72           0 :         ret = ENOMEM;
      73           0 :         goto done;
      74             :     }
      75             : 
      76           0 :     while (prompt[i] != '\0') {
      77           0 :        errno = 0;
      78           0 :        len = sss_atomic_write_s(STDOUT_FILENO, &prompt[i++], 1);
      79           0 :        if (len == -1) {
      80           0 :            ret = errno;
      81           0 :            DEBUG(SSSDBG_CRIT_FAILURE, "write failed [%d][%s].\n",
      82             :                                        ret, strerror(ret));
      83           0 :            goto done;
      84             :        }
      85             :     }
      86             : 
      87             : done:
      88           0 :     talloc_free(prompt);
      89           0 :     return ret;
      90             : }
      91             : 
      92           0 : static int seed_str_input(TALLOC_CTX *mem_ctx,
      93             :                           const char *req,
      94             :                           char **_input)
      95             : {
      96             :     char buf[BUFSIZE+1];
      97           0 :     size_t len = 0;
      98           0 :     size_t bytes_read = 0;
      99           0 :     int ret = EOK;
     100             : 
     101           0 :     ret = seed_prompt(req);
     102           0 :     if (ret != EOK) {
     103           0 :         return ret;
     104             :     }
     105             : 
     106           0 :     errno = 0;
     107           0 :     while ((bytes_read = sss_atomic_read_s(STDIN_FILENO, buf+len, 1)) != 0) {
     108           0 :         if (bytes_read == -1) {
     109           0 :             ret = errno;
     110           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "read failed [%d][%s].\n",
     111             :                                         ret, strerror(ret));
     112           0 :             return ret;
     113             :         }
     114           0 :         if (buf[len] == '\n' || len == BUFSIZE) {
     115           0 :             buf[len] = '\0';
     116           0 :             break;
     117             :         }
     118           0 :         len += bytes_read;
     119             :     }
     120             : 
     121           0 :     *_input = talloc_strdup(mem_ctx, buf);
     122           0 :     if (*_input == NULL) {
     123           0 :         ret = ENOMEM;
     124           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate input\n");
     125             :     }
     126             : 
     127           0 :     return ret;
     128             : }
     129             : 
     130           0 : static int seed_id_input(const char *req,
     131             :                          uid_t *_id_input)
     132             : {
     133             :     char buf[BUFSIZE+1];
     134           0 :     size_t len = 0;
     135           0 :     size_t bytes_read = 0;
     136           0 :     char *endptr = NULL;
     137           0 :     int ret = EOK;
     138             : 
     139           0 :     ret = seed_prompt(req);
     140           0 :     if (ret != EOK) {
     141           0 :         return ret;
     142             :     }
     143             : 
     144           0 :     errno = 0;
     145           0 :     while ((bytes_read = sss_atomic_read_s(STDIN_FILENO, buf+len, 1)) != 0) {
     146           0 :         if (bytes_read == -1) {
     147           0 :             ret = errno;
     148           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "read failed [%d][%s].\n",
     149             :                                         ret, strerror(ret));
     150           0 :             return ret;
     151             :         }
     152           0 :         if (buf[len] == '\n' || len == BUFSIZE) {
     153           0 :             buf[len] = '\0';
     154           0 :             break;
     155             :         }
     156           0 :         len += bytes_read;
     157             :     }
     158             : 
     159           0 :     if (isdigit(*buf)) {
     160           0 :         errno = 0;
     161           0 :         *_id_input = (uid_t)strtoll(buf, &endptr, 10);
     162           0 :         if (errno != 0) {
     163           0 :             ret = errno;
     164           0 :             DEBUG(SSSDBG_OP_FAILURE, "strtoll failed on [%s]: [%d][%s].\n",
     165             :                                       (char *)buf, ret, strerror(ret));
     166           0 :             return ret;
     167             :         }
     168           0 :         if (*endptr != '\0') {
     169           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     170             :                   "extra characters [%s] after ID [%"SPRIuid"]\n",
     171             :                    endptr, *_id_input);
     172             :         }
     173             :     } else {
     174           0 :         ret = EINVAL;
     175           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to get %s input.\n", req);
     176             :     }
     177             : 
     178           0 :     return ret;
     179             : }
     180             : 
     181           0 : static int seed_password_input_prompt(TALLOC_CTX *mem_ctx, char **_password)
     182             : {
     183           0 :     TALLOC_CTX *tmp_ctx = NULL;
     184           0 :     char *password = NULL;
     185           0 :     char *temp = NULL;
     186           0 :     int ret = EOK;
     187             : 
     188           0 :     tmp_ctx = talloc_new(NULL);
     189           0 :     if (tmp_ctx == NULL) {
     190           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate temp context\n");
     191           0 :         ret = ENOMEM;
     192           0 :         goto done;
     193             :     }
     194             : 
     195           0 :     temp = getpass("Enter temporary password:");
     196           0 :     if (temp == NULL) {
     197           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to get prompted password\n");
     198           0 :         ret = EINVAL;
     199           0 :         goto done;
     200             :     }
     201             : 
     202             :     /* Do not allow empty passwords */
     203           0 :     if (strlen(temp) == 0) {
     204           0 :         ERROR("Empty passwords are not allowed.\n");
     205           0 :         ret = EINVAL;
     206           0 :         goto done;
     207             :     }
     208             : 
     209           0 :     password = talloc_strdup(tmp_ctx, temp);
     210           0 :     if (password == NULL) {
     211           0 :         ret = ENOMEM;
     212           0 :         goto done;
     213             :     }
     214             : 
     215           0 :     talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
     216             : 
     217           0 :     temp = getpass("Enter temporary password again:");
     218           0 :     if (temp == NULL) {
     219           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to get prompted password\n");
     220           0 :         ret = EINVAL;
     221           0 :         goto done;
     222             :     }
     223             : 
     224           0 :     if (strncmp(temp,password,strlen(password)) != 0) {
     225           0 :         ERROR("Passwords do not match\n");
     226           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Provided passwords do not match\n");
     227           0 :         ret = EINVAL;
     228           0 :         goto done;
     229             :     }
     230             : 
     231           0 :     *_password = talloc_steal(mem_ctx, password);
     232             : 
     233             : done:
     234           0 :     talloc_free(tmp_ctx);
     235           0 :     return ret;
     236             : }
     237             : 
     238           0 : static int seed_password_input_file(TALLOC_CTX *mem_ctx,
     239             :                                     char *filename,
     240             :                                     char **_password)
     241             : {
     242           0 :     TALLOC_CTX *tmp_ctx = NULL;
     243           0 :     char *password = NULL;
     244           0 :     int len = 0;
     245             :     uint8_t buf[PASS_MAX+1];
     246           0 :     int fd = -1;
     247           0 :     int ret = EOK;
     248             :     int valid_i;
     249             :     int i;
     250             : 
     251           0 :     tmp_ctx = talloc_new(NULL);
     252           0 :     if (tmp_ctx == NULL) {
     253           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate temp context\n");
     254           0 :         ret = ENOMEM;
     255           0 :         goto done;
     256             :     }
     257             : 
     258           0 :     fd = open(filename, O_RDONLY);
     259           0 :     if (fd == -1) {
     260           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to open password file "
     261             :                                     "[%s] [%d][%s]\n",
     262             :                                     filename, errno, strerror(errno));
     263           0 :         ret = EINVAL;
     264           0 :         goto done;
     265             :     }
     266             : 
     267           0 :     errno = 0;
     268           0 :     len = sss_atomic_read_s(fd, buf, PASS_MAX + 1);
     269           0 :     if (len == -1) {
     270           0 :         ret = errno;
     271           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Failed to read password from file "
     272             :                                      "[%s] [%d][%s]\n",
     273             :                                      filename, ret, strerror(ret));
     274           0 :         close(fd);
     275           0 :         goto done;
     276             :     }
     277             : 
     278           0 :     close(fd);
     279             : 
     280           0 :     if (len > PASS_MAX) {
     281           0 :         ERROR("Password file too big.\n");
     282           0 :         ret = EINVAL;
     283           0 :         goto done;
     284             :     }
     285             : 
     286           0 :     buf[len] = '\0';
     287             : 
     288             :     /* Only the first line is valid (without '\n'). */
     289           0 :     for (valid_i = -1; valid_i + 1 < len; valid_i++) {
     290           0 :         if (buf[valid_i + 1] == '\n') {
     291           0 :             buf[valid_i + 1] = '\0';
     292           0 :             break;
     293             :         }
     294             :     }
     295             : 
     296             :     /* Do not allow empty passwords. */
     297           0 :     if (valid_i < 0) {
     298           0 :         ERROR("Empty passwords are not allowed.\n");
     299           0 :         ret = EINVAL;
     300           0 :         goto done;
     301             :     }
     302             : 
     303             :     /* valid_i is the last valid index of the password followed by \0.
     304             :      * If characters other than \n occur int the rest of the file, it
     305             :      * is an error. */
     306           0 :     for (i = valid_i + 2; i < len; i++) {
     307           0 :         if (buf[i] != '\n') {
     308           0 :             ERROR("Multi-line passwords are not allowed.\n");
     309           0 :             ret = EINVAL;
     310           0 :             goto done;
     311             :         }
     312             :     }
     313             : 
     314           0 :     password = talloc_strdup(tmp_ctx, (char *)buf);
     315           0 :     if (password == NULL) {
     316           0 :         ret = ENOMEM;
     317           0 :         goto done;
     318             :     }
     319             : 
     320           0 :     *_password = talloc_steal(mem_ctx, password);
     321             : 
     322             : done:
     323           0 :     talloc_free(tmp_ctx);
     324           0 :     return ret;
     325             : }
     326             : 
     327           0 : static int seed_interactive_input(TALLOC_CTX *mem_ctx,
     328             :                                   struct user_ctx *uctx,
     329             :                                   struct user_ctx **_uctx)
     330             : {
     331           0 :     struct user_ctx *input_uctx = NULL;
     332           0 :     int ret = EOK;
     333             : 
     334           0 :     input_uctx = talloc_zero(NULL, struct user_ctx);
     335           0 :     if (input_uctx == NULL) {
     336           0 :         ret = ENOMEM;
     337           0 :         goto done;
     338             :     }
     339             : 
     340           0 :     if (uctx->name == NULL) {
     341           0 :         ret = seed_str_input(input_uctx, _("username"), &input_uctx->name);
     342           0 :         if (ret != EOK) {
     343           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     344             :                   "Username interactive input failed.\n");
     345           0 :             goto done;
     346             :         }
     347             :     } else {
     348           0 :         input_uctx->name = talloc_strdup(input_uctx, uctx->name);
     349           0 :         if (input_uctx->name == NULL) {
     350           0 :             ret = ENOMEM;
     351           0 :             goto done;
     352             :         }
     353             :     }
     354             : 
     355           0 :     if (uctx->uid == 0) {
     356           0 :         ret = seed_id_input(_("UID"), &input_uctx->uid);
     357           0 :         if (ret != EOK) {
     358           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "UID interactive input failed.\n");
     359           0 :             goto done;
     360             :         }
     361             :     } else {
     362           0 :         input_uctx->uid = uctx->uid;
     363             :     }
     364             : 
     365           0 :     if (uctx->gid == 0) {
     366           0 :         ret = seed_id_input(_("GID"), &input_uctx->gid);
     367           0 :         if (ret != EOK) {
     368           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "GID interactive input failed.\n");
     369           0 :             goto done;
     370             :         }
     371             :     } else {
     372           0 :         input_uctx->gid = uctx->gid;
     373             :     }
     374             : 
     375           0 :     if (uctx->gecos == NULL) {
     376           0 :         ret = seed_str_input(input_uctx, _("user comment (gecos)"),
     377             :                              &input_uctx->gecos);
     378           0 :         if (ret != EOK) {
     379           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Gecos interactive input failed.\n");
     380           0 :             goto done;
     381             :         }
     382             :     } else {
     383           0 :         input_uctx->gecos = talloc_strdup(input_uctx, uctx->gecos);
     384           0 :         if (input_uctx->gecos == NULL) {
     385           0 :             ret = ENOMEM;
     386           0 :             goto done;
     387             :         }
     388             :     }
     389             : 
     390           0 :     if (uctx->home == NULL) {
     391           0 :         ret = seed_str_input(input_uctx, _("home directory"),
     392             :                              &input_uctx->home);
     393           0 :         if (ret != EOK) {
     394           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     395             :                   "Home directory interactive input fialed.\n");
     396           0 :             goto done;
     397             :         }
     398             :     } else {
     399           0 :         input_uctx->home = talloc_strdup(input_uctx, uctx->home);
     400           0 :         if (input_uctx->home == NULL) {
     401           0 :             ret = ENOMEM;
     402           0 :             goto done;
     403             :         }
     404             :     }
     405             : 
     406           0 :     if (uctx->shell == NULL) {
     407           0 :         ret = seed_str_input(input_uctx, _("user login shell"),
     408             :                              &input_uctx->shell);
     409           0 :         if (ret != EOK) {
     410           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Shell interactive input failed\n");
     411           0 :             goto done;
     412             :         }
     413             :     } else {
     414           0 :         input_uctx->shell = talloc_strdup(input_uctx, uctx->shell);
     415           0 :         if (input_uctx->shell == NULL) {
     416           0 :             ret = ENOMEM;
     417           0 :             goto done;
     418             :         }
     419             :     }
     420             : 
     421             : done:
     422           0 :     if (ret == EOK) {
     423           0 :         *_uctx = talloc_steal(mem_ctx, input_uctx);
     424             :     } else {
     425           0 :         ERROR("Interactive input failed.\n");
     426           0 :         talloc_zfree(input_uctx);
     427             :     }
     428           0 :     return ret;
     429             : }
     430             : 
     431           0 : static int seed_init(TALLOC_CTX *mem_ctx,
     432             :                      const int argc,
     433             :                      const char **argv,
     434             :                      struct seed_ctx **_sctx)
     435             : {
     436           0 :     TALLOC_CTX *tmp_ctx = NULL;
     437           0 :     int pc_debug = SSSDBG_DEFAULT;
     438           0 :     const char *pc_domain = NULL;
     439           0 :     const char *pc_name = NULL;
     440           0 :     uid_t pc_uid = 0;
     441           0 :     gid_t pc_gid = 0;
     442           0 :     const char *pc_gecos = NULL;
     443           0 :     const char *pc_home = NULL;
     444           0 :     const char *pc_shell = NULL;
     445           0 :     const char *pc_password_file = NULL;
     446             : 
     447           0 :     struct seed_ctx *sctx = NULL;
     448             : 
     449           0 :     int ret = EOK;
     450             : 
     451           0 :     poptContext pc = NULL;
     452           0 :     struct poptOption options[] = {
     453             :         POPT_AUTOHELP
     454             :         { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, 0,
     455           0 :          _("The debug level to run with"), NULL },
     456           0 :         { "domain", 'D', POPT_ARG_STRING, &pc_domain, 0, _("Domain"), NULL },
     457           0 :         { "username", 'n', POPT_ARG_STRING, &pc_name, 0, _("Username"), NULL},
     458           0 :         { "uid",   'u', POPT_ARG_INT, &pc_uid, 0, _("User UID"), NULL },
     459           0 :         { "gid",   'g', POPT_ARG_INT, &pc_gid, 0, _("User GID"), NULL },
     460             :         { "gecos", 'c', POPT_ARG_STRING, &pc_gecos, 0,
     461           0 :          _("Comment string"), NULL},
     462             :         { "home",  'h', POPT_ARG_STRING, &pc_home, 0,
     463           0 :          _("Home directory"), NULL },
     464           0 :         { "shell", 's', POPT_ARG_STRING, &pc_shell, 0, _("Login Shell"), NULL },
     465             :         { "interactive", 'i', POPT_ARG_NONE, NULL, 'i',
     466           0 :          _("Use interactive mode to enter user data"), NULL },
     467             :         { "password-file", 'p', POPT_ARG_STRING, &pc_password_file, 0,
     468           0 :          _("File from which user's password is read "
     469             :            "(default is to prompt for password)"),NULL },
     470             :         POPT_TABLEEND
     471             :     };
     472             : 
     473             :     /* init contexts */
     474           0 :     tmp_ctx = talloc_new(NULL);
     475           0 :     if (tmp_ctx == NULL) {
     476           0 :         ret = ENOMEM;
     477           0 :         goto fini;
     478             :     }
     479             : 
     480           0 :     sctx = talloc_zero(tmp_ctx, struct seed_ctx);
     481           0 :     if (sctx == NULL) {
     482           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate tools context\n");
     483           0 :         ret = ENOMEM;
     484           0 :         goto fini;
     485             :     }
     486             : 
     487           0 :     sctx->uctx = talloc_zero(sctx, struct user_ctx);
     488           0 :     if (sctx->uctx == NULL) {
     489           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate user data context\n");
     490           0 :         ret = ENOMEM;
     491           0 :         goto fini;
     492             :     }
     493             : 
     494           0 :     debug_prg_name = argv[0];
     495           0 :     ret = set_locale();
     496           0 :     if (ret != EOK) {
     497           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "set_locale failed (%d): %s\n",
     498             :                                     ret, strerror(ret));
     499           0 :         ERROR("Error setting the locale\n");
     500           0 :         ret = EINVAL;
     501           0 :         goto fini;
     502             :     }
     503             : 
     504             :     /* parse arguments */
     505           0 :     pc = poptGetContext(NULL, argc, argv, options, 0);
     506           0 :     if (argc < 2) {
     507           0 :         poptPrintUsage(pc,stderr,0);
     508           0 :         ret = EINVAL;
     509           0 :         goto fini;
     510             :     }
     511             : 
     512           0 :     poptSetOtherOptionHelp(pc, "[OPTIONS] -D <domain> -n <username>");
     513           0 :     while ((ret = poptGetNextOpt(pc)) > 0) {
     514           0 :         switch (ret) {
     515             :             case 'i':
     516           0 :                 DEBUG(SSSDBG_TRACE_INTERNAL, "Interactive mode selected\n");
     517           0 :                 sctx->interact = true;
     518           0 :                 break;
     519             :         }
     520             :     }
     521             : 
     522           0 :     if (ret != -1) {
     523           0 :         BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini);
     524             :     }
     525             : 
     526           0 :     DEBUG_CLI_INIT(pc_debug);
     527             : 
     528           0 :     CHECK_ROOT(ret, argv[0]);
     529             : 
     530             :     /* check username provided */
     531           0 :     if (pc_name == NULL) {
     532           0 :         BAD_POPT_PARAMS(pc, _("Username must be specified\n"), ret, fini);
     533             :     }
     534             : 
     535           0 :     sctx->uctx->name = talloc_strdup(sctx->uctx, pc_name);
     536           0 :     if (sctx->uctx->name == NULL) {
     537           0 :         ret = ENOMEM;
     538           0 :         goto fini;
     539             :     }
     540             : 
     541             :     /* check domain is provided */
     542           0 :     if (pc_domain == NULL) {
     543           0 :         BAD_POPT_PARAMS(pc, _("Domain must be specified.\n"), ret, fini);
     544             :     }
     545             : 
     546           0 :     sctx->uctx->domain_name = talloc_strdup(sctx->uctx, pc_domain);
     547           0 :     if (sctx->uctx->domain_name == NULL) {
     548           0 :         ret = ENOMEM;
     549           0 :         goto fini;
     550             :     }
     551             : 
     552           0 :     poptFreeContext(pc);
     553             : 
     554           0 :     ret = EOK;
     555             : 
     556             :     /* copy all information provided from popt */
     557           0 :     sctx->uctx->uid = pc_uid;
     558           0 :     sctx->uctx->gid = pc_gid;
     559           0 :     if (pc_gecos != NULL) {
     560           0 :         sctx->uctx->gecos = talloc_strdup(sctx->uctx, pc_gecos);
     561           0 :         if (sctx->uctx->gecos == NULL) {
     562           0 :             ret = ENOMEM;
     563           0 :             goto fini;
     564             :         }
     565             :     }
     566           0 :     if (pc_home != NULL) {
     567           0 :         sctx->uctx->home = talloc_strdup(sctx->uctx, pc_home);
     568           0 :         if (sctx->uctx->home == NULL) {
     569           0 :             ret = ENOMEM;
     570           0 :             goto fini;
     571             :         }
     572             :     }
     573           0 :     if (pc_shell != NULL) {
     574           0 :         sctx->uctx->shell = talloc_strdup(sctx->uctx, pc_shell);
     575           0 :         if (sctx->uctx->shell == NULL) {
     576           0 :             ret = ENOMEM;
     577           0 :             goto fini;
     578             :         }
     579             :     }
     580             : 
     581             :     /* check if password file provided */
     582           0 :     if (pc_password_file != NULL) {
     583           0 :         sctx->password_file = talloc_strdup(sctx, pc_password_file);
     584           0 :         if (sctx->password_file == NULL) {
     585           0 :             ret = ENOMEM;
     586           0 :             goto fini;
     587             :         }
     588           0 :         sctx->password_method = PASS_FILE;
     589             :     } else {
     590           0 :         sctx->password_method = PASS_PROMPT;
     591             :     }
     592             : 
     593           0 :     *_sctx = talloc_steal(mem_ctx, sctx);
     594             : 
     595             : fini:
     596           0 :     talloc_free(tmp_ctx);
     597           0 :     return ret;
     598             : }
     599             : 
     600           0 : static int seed_init_db(TALLOC_CTX *mem_ctx,
     601             :                         const char *domain_name,
     602             :                         struct confdb_ctx **_confdb,
     603             :                         struct sss_domain_info **_domain,
     604             :                         struct sysdb_ctx **_sysdb)
     605             : {
     606           0 :     TALLOC_CTX *tmp_ctx = NULL;
     607           0 :     char *confdb_path = NULL;
     608           0 :     struct confdb_ctx *confdb = NULL;
     609           0 :     struct sss_domain_info *domain = NULL;
     610           0 :     int ret = EOK;
     611             : 
     612           0 :     tmp_ctx = talloc_new(NULL);
     613           0 :     if (tmp_ctx == NULL) {
     614           0 :         ret = ENOMEM;
     615           0 :         goto done;
     616             :     }
     617             : 
     618             :     /* setup confdb */
     619           0 :     confdb_path = talloc_asprintf(tmp_ctx, "%s/%s", DB_PATH, CONFDB_FILE);
     620           0 :     if (confdb_path == NULL) {
     621           0 :         ret = ENOMEM;
     622           0 :         goto done;
     623             :     }
     624             : 
     625           0 :     ret = confdb_init(tmp_ctx, &confdb, confdb_path);
     626           0 :     if (ret != EOK) {
     627           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     628             :               "Could not initialize connection to the confdb\n");
     629           0 :         ERROR("Could not initialize connection to the confdb\n");
     630           0 :         goto done;
     631             :     }
     632             : 
     633           0 :     ret = sssd_domain_init(tmp_ctx, confdb, domain_name, DB_PATH, &domain);
     634           0 :     if (ret != EOK) {
     635           0 :         SYSDB_VERSION_ERROR(ret);
     636           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     637             :               "Could not initialize connection to domain '%s' in sysdb.%s\n",
     638             :                domain_name, ret == ENOENT ? " Domain not found." : "");
     639           0 :         ERROR("Could not initialize connection to domain '%1$s' in sysdb.%2$s\n",
     640             :               domain_name, ret == ENOENT ? " Domain not found." : "");
     641             : 
     642           0 :         goto done;
     643             :     }
     644             : 
     645           0 :     *_confdb = talloc_steal(mem_ctx, confdb);
     646           0 :     *_domain = domain;
     647           0 :     *_sysdb = domain->sysdb;
     648             : 
     649             : done:
     650           0 :     talloc_free(tmp_ctx);
     651           0 :     return ret;
     652             : }
     653             : 
     654           0 : static int seed_domain_user_info(const char *name,
     655             :                                  const char *domain_name,
     656             :                                  struct sss_domain_info *domain,
     657             :                                  bool *is_cached)
     658             : {
     659           0 :     TALLOC_CTX *tmp_ctx = NULL;
     660           0 :     char *fq_name = NULL;
     661           0 :     struct passwd *passwd = NULL;
     662           0 :     struct ldb_result *res = NULL;
     663           0 :     int ret = EOK;
     664             : 
     665           0 :     tmp_ctx = talloc_new(NULL);
     666           0 :     if (tmp_ctx == NULL) {
     667           0 :         ret = ENOMEM;
     668           0 :         goto done;
     669             :     }
     670             : 
     671           0 :     fq_name = talloc_asprintf(tmp_ctx, "%s@%s", name, domain_name);
     672           0 :     if (fq_name == NULL) {
     673           0 :         ret = ENOMEM;
     674           0 :         goto done;
     675             :     }
     676             : 
     677           0 :     errno = 0;
     678           0 :     passwd = getpwnam(fq_name);
     679           0 :     if (passwd == NULL) {
     680           0 :         ret = errno;
     681           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "getpwnam failed [%d] [%s]\n",
     682             :                                      ret, strerror(ret));
     683           0 :         goto done;
     684             :     }
     685             : 
     686             :     /* look for user in cache */
     687           0 :     ret = sysdb_getpwnam(tmp_ctx, domain, name, &res);
     688           0 :     if (ret != EOK) {
     689           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     690             :               "Couldn't lookup user (%s) in the cache\n", name);
     691           0 :         goto done;
     692             :     }
     693             : 
     694           0 :     if (res->count == 0) {
     695           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
     696             :               "User (%s) wasn't found in the cache\n", name);
     697           0 :         *is_cached = false;
     698           0 :         ret = ENOENT;
     699           0 :         goto done;
     700           0 :     } else if (res->count > 1) {
     701           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     702             :               "Multiple user (%s) entries were found in the cache\n", name);
     703           0 :         ret = EINVAL;
     704           0 :         goto done;
     705             :     } else {
     706           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "User found in cache\n");
     707           0 :         *is_cached = true;
     708             : 
     709           0 :         errno = 0;
     710           0 :         ret = initgroups(fq_name, passwd->pw_gid);
     711           0 :         if (ret != EOK) {
     712           0 :             ret = errno;
     713           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "initgroups failed [%d] [%s]\n",
     714             :                                          ret, strerror(ret));
     715           0 :             goto done;
     716             :         }
     717             :     }
     718             : 
     719             : done:
     720           0 :     if (ret == ENOMEM) {
     721           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate user information\n");
     722             :     }
     723           0 :     talloc_zfree(tmp_ctx);
     724           0 :     return ret;
     725             : }
     726             : 
     727           0 : static int seed_cache_user(struct seed_ctx *sctx)
     728             : {
     729           0 :     bool in_transaction = false;
     730           0 :     int ret = EOK;
     731             :     errno_t sret;
     732             : 
     733           0 :     ret = sysdb_transaction_start(sctx->sysdb);
     734           0 :     if (ret != EOK) {
     735           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb transaction start failure\n");
     736           0 :         goto done;
     737             :     }
     738             : 
     739           0 :     in_transaction = true;
     740             : 
     741           0 :     if (sctx->user_cached == false) {
     742           0 :         ret = sysdb_add_user(sctx->domain, sctx->uctx->name,
     743           0 :                              sctx->uctx->uid, sctx->uctx->gid,
     744           0 :                              sctx->uctx->gecos, sctx->uctx->home,
     745           0 :                              sctx->uctx->shell, NULL, NULL, 0, 0);
     746           0 :         if (ret != EOK) {
     747           0 :             DEBUG(SSSDBG_OP_FAILURE,
     748             :                   "Failed to add user to the cache. (%d)[%s]\n",
     749             :                    ret, strerror(ret));
     750           0 :             ERROR("Failed to create user cache entry\n");
     751           0 :             goto done;
     752             :         }
     753             :     }
     754             : 
     755           0 :     ret = sysdb_cache_password(sctx->domain, sctx->uctx->name,
     756           0 :                                sctx->uctx->password);
     757           0 :     if (ret != EOK) {
     758           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password. (%d)[%s]\n",
     759             :                                   ret, strerror(ret));
     760           0 :         ERROR("Failed to cache password\n");
     761           0 :         goto done;
     762             :     }
     763             : 
     764           0 :     ret = sysdb_transaction_commit(sctx->sysdb);
     765           0 :     if (ret != EOK) {
     766           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb transaction commit failure\n");
     767           0 :         goto done;
     768             :     }
     769             : 
     770           0 :     in_transaction = false;
     771             : 
     772             : done:
     773           0 :     if (in_transaction == true) {
     774           0 :         sret = sysdb_transaction_cancel(sctx->sysdb);
     775           0 :         if (sret != EOK) {
     776           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to cancel transaction\n");
     777             :         }
     778             :     }
     779             : 
     780           0 :     return ret;
     781             : }
     782             : 
     783           0 : int main(int argc, const char **argv)
     784             : {
     785           0 :     struct seed_ctx *sctx = NULL;
     786           0 :     struct user_ctx *input_uctx = NULL;
     787           0 :     int ret = EOK;
     788             : 
     789             :     /* initialize seed context and parse options */
     790           0 :     ret = seed_init(sctx, argc, argv, &sctx);
     791           0 :     if (ret != EOK) {
     792           0 :         DEBUG(SSSDBG_OP_FAILURE,"Seed init failed [%d][%s]\n",
     793             :                                  ret, strerror(ret));
     794           0 :         goto done;
     795             :     }
     796             : 
     797             :     /* set up confdb,sysdb and domain */
     798           0 :     ret = seed_init_db(sctx, sctx->uctx->domain_name, &sctx->confdb,
     799           0 :                        &sctx->domain, &sctx->sysdb);
     800           0 :     if (ret != EOK) {
     801           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize db and domain\n");
     802           0 :         goto done;
     803             :     }
     804             : 
     805             :     /* get user info from domain */
     806           0 :     ret = seed_domain_user_info(sctx->uctx->name, sctx->uctx->domain_name,
     807           0 :                                 sctx->domain, &sctx->user_cached);
     808           0 :     if (ret != EOK) {
     809           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed lookup of user [%s] in domain [%s]\n",
     810             :                                   sctx->uctx->name, sctx->uctx->domain_name);
     811             :     }
     812             : 
     813             :     /* interactive mode to fill in user information */
     814           0 :     if (sctx->interact == true) {
     815           0 :         if (sctx->user_cached == true) {
     816           0 :             ERROR(_("User entry already exists in the cache.\n"));
     817           0 :             ret = EEXIST;
     818           0 :             goto done;
     819             :         } else {
     820           0 :             ret = seed_interactive_input(sctx, sctx->uctx, &input_uctx);
     821           0 :             if (ret != EOK) {
     822           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Failed to get seed input.\n");
     823           0 :                 ret = EINVAL;
     824           0 :                 goto done;
     825             :             }
     826           0 :             talloc_zfree(sctx->uctx);
     827           0 :             sctx->uctx = input_uctx;
     828             :         }
     829             :     }
     830             : 
     831           0 :     if (sctx->user_cached == false) {
     832           0 :         if (sctx->uctx->uid == 0 || sctx->uctx->gid == 0) {
     833             :             /* require username, UID, and GID to continue */
     834           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Not enough information provided\n");
     835           0 :             ERROR("UID and primary GID not provided.\n");
     836           0 :             ret = EINVAL;
     837           0 :             goto done;
     838             :         }
     839             :     }
     840             : 
     841             :     /* password input */
     842           0 :     if (sctx->password_method == PASS_FILE) {
     843           0 :         ret = seed_password_input_file(sctx->uctx, sctx->password_file,
     844           0 :                                        &sctx->uctx->password);
     845           0 :         if (ret != EOK) {
     846           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Password input failure\n");
     847           0 :             goto done;
     848             :         }
     849             :     } else {
     850           0 :         ret = seed_password_input_prompt(sctx->uctx, &sctx->uctx->password);
     851           0 :         if (ret != EOK) {
     852           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Password input failure\n");
     853           0 :             goto done;
     854             :         }
     855             :     }
     856             : 
     857             :     /* Add user info and password to sysdb cache */
     858           0 :     ret = seed_cache_user(sctx);
     859           0 :     if (ret != EOK) {
     860           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Failed to modify cache.\n");
     861           0 :         goto done;
     862             :     } else {
     863           0 :         if (sctx->user_cached == false) {
     864           0 :             printf(_("User cache entry created for %1$s\n"), sctx->uctx->name);
     865             :         }
     866           0 :         printf(_("Temporary password added to cache entry for %1$s\n"),
     867           0 :                  sctx->uctx->name);
     868             :     }
     869             : 
     870             : done:
     871           0 :     talloc_zfree(sctx);
     872           0 :     if (ret != EOK) {
     873           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Exit error: [%d] [%s]\n",
     874             :                                       ret, strerror(ret));
     875           0 :         ret = EXIT_FAILURE;
     876             :     } else {
     877           0 :         ret = EXIT_SUCCESS;
     878             :     }
     879           0 :     exit(ret);
     880             : }

Generated by: LCOV version 1.10