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 : }
|