1 /* 2 * Copyright (c)2004,2015 The DragonFly Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * Neither the name of the DragonFly Project nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 * OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * fn_configure.c 36 * Configuration functions for installer. 37 * This includes both Configure the LiveCD Environment, and 38 * Configure an Installed System (there is considerable overlap.) 39 * $Id: fn_configure.c,v 1.82 2005/03/25 05:24:00 cpressey Exp $ 40 */ 41 42 #include <sys/stat.h> 43 #include <sys/types.h> 44 45 #include <ctype.h> 46 #include <dirent.h> 47 #include <fcntl.h> 48 #include <libgen.h> 49 #include <stdarg.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <time.h> 54 #include <unistd.h> 55 56 #ifdef ENABLE_NLS 57 #include <libintl.h> 58 #define _(String) gettext (String) 59 #else 60 #define _(String) (String) 61 #endif 62 63 #include "libaura/mem.h" 64 #include "libaura/dict.h" 65 #include "libaura/fspred.h" 66 67 #include "libdfui/dfui.h" 68 #include "libdfui/system.h" 69 70 #include "libinstaller/commands.h" 71 #include "libinstaller/confed.h" 72 #include "libinstaller/diskutil.h" 73 #include "libinstaller/functions.h" 74 #include "libinstaller/uiutil.h" 75 76 #include "fn.h" 77 #include "flow.h" 78 #include "pathnames.h" 79 80 struct config_vars *rc_conf; 81 82 static const char *yes_to_y(const char *); 83 84 /** CONFIGURE FUNCTIONS **/ 85 86 #define GECOS_NOT_ALLOWED ":,\\\"" 87 #define FILENAME_NOT_ALLOWED ":;`~!#$^&*()={}[]\\|?<>'\" " 88 #define MEMBERSHIPS_NOT_ALLOWED ":;`~!@#$%^&*()+={}[]\\|/?<>'\" " 89 #define USERNAME_NOT_ALLOWED (MEMBERSHIPS_NOT_ALLOWED ",") 90 91 void 92 fn_add_user(struct i_fn_args *a) 93 { 94 struct dfui_dataset *ds, *new_ds; 95 struct dfui_form *f; 96 struct dfui_response *r; 97 struct commands *cmds; 98 struct command *cmd; 99 const char *username, *home, *passwd_1, *passwd_2, *gecos; 100 const char *shell, *uid, *group, *groups; 101 const char *passwd_env = "passwd"; 102 int done = 0; 103 104 f = dfui_form_create( 105 "add_user", 106 _("Add user"), 107 _("Here you can add a user to an installed system.\n\n" 108 "You can leave the Home Directory, User ID, and Login Group " 109 "fields empty if you want these items to be automatically " 110 "allocated by the system."), 111 "", 112 "f", "username", _("Username"), 113 _("Enter the username the user will log in as"), "", 114 "f", "gecos", _("Real Name"), 115 _("Enter the real name (or GECOS field) of this user"), "", 116 "f", "passwd_1", _("Password"), 117 _("Enter the user's password (will not be displayed)"), "", 118 "p", "obscured", "true", 119 "f", "passwd_2", _("Password (Again)"), 120 _("Re-enter the user's password to confirm"), "", 121 "p", "obscured", "true", 122 "f", "shell", _("Shell"), 123 _("Enter the full path to the user's shell program"), "", 124 "f", "home", _("Home Directory"), 125 _("Enter the full path to the user's home directory, or leave blank"), "", 126 "f", "uid", _("User ID"), 127 _("Enter this account's numeric user id, or leave blank"), "", 128 "f", "group", _("Login Group"), 129 _("Enter the primary group for this account, or leave blank"), "", 130 "f", "groups", _("Other Group Memberships"), 131 _("Enter a comma-separated list of other groups " 132 "that this user should belong to"), "", 133 "a", "ok", _("Accept and Add"), "", "", 134 "a", "cancel", _("Return to Configure Menu"), "", "", 135 "p", "accelerator", "ESC", 136 NULL 137 ); 138 139 ds = dfui_dataset_new(); 140 dfui_dataset_celldata_add(ds, "username", ""); 141 dfui_dataset_celldata_add(ds, "gecos", ""); 142 dfui_dataset_celldata_add(ds, "passwd_1", ""); 143 dfui_dataset_celldata_add(ds, "passwd_2", ""); 144 dfui_dataset_celldata_add(ds, "shell", "/bin/tcsh"); 145 dfui_dataset_celldata_add(ds, "home", ""); 146 dfui_dataset_celldata_add(ds, "uid", ""); 147 dfui_dataset_celldata_add(ds, "group", ""); 148 dfui_dataset_celldata_add(ds, "groups", ""); 149 dfui_form_dataset_add(f, ds); 150 151 while (!done) { 152 if (!dfui_be_present(a->c, f, &r)) 153 abort_backend(); 154 155 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { 156 done = 1; 157 dfui_response_free(r); 158 break; 159 } 160 161 new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r)); 162 dfui_form_datasets_free(f); 163 dfui_form_dataset_add(f, new_ds); 164 165 /* Fetch form field values. */ 166 167 username = dfui_dataset_get_value(new_ds, "username"); 168 home = dfui_dataset_get_value(new_ds, "home"); 169 gecos = dfui_dataset_get_value(new_ds, "gecos"); 170 shell = dfui_dataset_get_value(new_ds, "shell"); 171 passwd_1 = dfui_dataset_get_value(new_ds, "passwd_1"); 172 passwd_2 = dfui_dataset_get_value(new_ds, "passwd_2"); 173 uid = dfui_dataset_get_value(new_ds, "uid"); 174 group = dfui_dataset_get_value(new_ds, "group"); 175 groups = dfui_dataset_get_value(new_ds, "groups"); 176 177 if (strlen(username) == 0) { 178 inform(a->c, _("You must enter a username.")); 179 done = 0; 180 } else if (strcmp(passwd_1, passwd_2) != 0) { 181 inform(a->c, _("The passwords do not match.")); 182 done = 0; 183 } else if (!assert_clean(a->c, _("Username"), username, USERNAME_NOT_ALLOWED) || 184 !assert_clean(a->c, _("Real Name"), gecos, GECOS_NOT_ALLOWED) || 185 !assert_clean(a->c, _("Shell"), shell, FILENAME_NOT_ALLOWED) || 186 !assert_clean(a->c, _("Home Directory"), home, FILENAME_NOT_ALLOWED) || 187 !assert_clean(a->c, _("User ID"), uid, USERNAME_NOT_ALLOWED) || 188 !assert_clean(a->c, _("Login Group"), group, USERNAME_NOT_ALLOWED) || 189 !assert_clean(a->c, _("Group Memberships"), groups, MEMBERSHIPS_NOT_ALLOWED)) { 190 done = 0; 191 } else if (setenv(passwd_env, passwd_1, 1) != 0) { 192 inform(a->c, _("setenv() failed.")); 193 done = 0; 194 } else if (!is_program("%s%s", a->os_root, shell) && 195 strcmp(shell, "/nonexistent") != 0) { 196 inform(a->c, _("Chosen shell does not exist on the system.")); 197 done = 0; 198 } else { 199 cmds = commands_new(); 200 201 command_add(cmds, "%s%s %smnt/ /%s useradd " 202 "'%s' %s%s %s%s -c \"%s\" %s%s -s %s %s%s %s", 203 a->os_root, cmd_name(a, "CHROOT"), 204 a->os_root, cmd_name(a, "PW"), 205 username, 206 strlen(uid) == 0 ? "" : "-u ", uid, 207 strlen(group) == 0 ? "" : "-g ", group, 208 gecos, 209 strlen(home) == 0 ? "" : "-d ", home, 210 shell, 211 strlen(groups) == 0 ? "" : "-G ", groups, 212 (strlen(home) == 0 || !is_dir("%s", home)) ? 213 "-m -k /usr/share/skel" : ""); 214 215 cmd = command_add(cmds, "%s%s \"$%s\" | " 216 "%s%s %smnt/ /%s usermod '%s' -h 0", 217 a->os_root, cmd_name(a, "ECHO"), 218 passwd_env, 219 a->os_root, cmd_name(a, "CHROOT"), 220 a->os_root, cmd_name(a, "PW"), 221 username); 222 command_set_desc(cmd, _("Setting password...")); 223 224 if (commands_execute(a, cmds)) { 225 inform(a->c, _("User `%s' was added."), username); 226 done = 1; 227 } else { 228 inform(a->c, _("User was not successfully added.")); 229 done = 0; 230 } 231 232 unsetenv(passwd_env); 233 commands_free(cmds); 234 } 235 236 dfui_response_free(r); 237 } 238 239 dfui_form_free(f); 240 } 241 242 void 243 fn_root_passwd(struct i_fn_args *a) 244 { 245 struct dfui_dataset *ds, *new_ds; 246 struct dfui_form *f; 247 struct dfui_response *r; 248 struct commands *cmds; 249 struct command *cmd; 250 const char *root_passwd_1, *root_passwd_2; 251 const char *passwd_env = "passwd"; 252 int done = 0; 253 254 f = dfui_form_create( 255 "root_passwd", 256 _("Set Root Password"), 257 _("Here you can set the super-user (root) password."), 258 "", 259 260 "f", "root_passwd_1", _("Root password"), 261 _("Enter the root password you would like to use"), "", 262 "p", "obscured", "true", 263 "f", "root_passwd_2", _("Root password again"), 264 _("Enter the root password again to confirm"), "", 265 "p", "obscured", "true", 266 267 "a", "ok", _("Accept and Set Password"), "", "", 268 "a", "cancel", _("Return to Configure Menu"), "", "", 269 "p", "accelerator", "ESC", 270 271 NULL 272 ); 273 274 ds = dfui_dataset_new(); 275 dfui_dataset_celldata_add(ds, "root_passwd_1", ""); 276 dfui_dataset_celldata_add(ds, "root_passwd_2", ""); 277 dfui_form_dataset_add(f, ds); 278 279 while (!done) { 280 if (!dfui_be_present(a->c, f, &r)) 281 abort_backend(); 282 283 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { 284 done = 1; 285 dfui_response_free(r); 286 break; 287 } 288 289 new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r)); 290 dfui_form_datasets_free(f); 291 dfui_form_dataset_add(f, new_ds); 292 293 root_passwd_1 = dfui_dataset_get_value(new_ds, "root_passwd_1"); 294 root_passwd_2 = dfui_dataset_get_value(new_ds, "root_passwd_2"); 295 296 if (strlen(root_passwd_1) == 0) { 297 inform(a->c, _("You must enter a password.")); 298 done = 0; 299 } else if (strcmp(root_passwd_1, root_passwd_2) != 0) { 300 inform(a->c, _("The passwords do not match.")); 301 done = 0; 302 } else if (setenv(passwd_env, root_passwd_1, 1) != 0) { 303 inform(a->c, _("setenv() failed.")); 304 done = 0; 305 } else { 306 cmds = commands_new(); 307 cmd = command_add(cmds, "%s%s \"$%s\" | " 308 "%s%s %smnt/ /%s usermod root -h 0", 309 a->os_root, cmd_name(a, "ECHO"), 310 passwd_env, 311 a->os_root, cmd_name(a, "CHROOT"), 312 a->os_root, cmd_name(a, "PW")); 313 command_set_desc(cmd, _("Setting password...")); 314 if (commands_execute(a, cmds)) { 315 inform(a->c, _("The root password has been changed.")); 316 done = 1; 317 } else { 318 inform(a->c, _("An error occurred when " 319 "setting the root password.")); 320 done = 0; 321 } 322 unsetenv(passwd_env); 323 commands_free(cmds); 324 } 325 326 dfui_response_free(r); 327 } 328 329 dfui_form_free(f); 330 } 331 332 void 333 fn_get_passphrase(struct i_fn_args *a) 334 { 335 struct dfui_dataset *ds, *new_ds; 336 struct dfui_form *f; 337 struct dfui_response *r; 338 const char *passphrase_1, *passphrase_2; 339 int fd; 340 int done = 0; 341 342 f = dfui_form_create( 343 "crypt_passphrase", 344 _("Set Passphrase For Encryption"), 345 _("Please specify the passphrase to be used for the encrypted " 346 "filesystems.\n\n" 347 "Please note that in the LiveCD environment the keymap is set to " 348 "\"US ISO\". " 349 "If you prefer a different keymap for entering the passphrase " 350 "here, you will need to set it manually using kbdcontrol(1)."), 351 "", 352 353 "f", "passphrase_1", _("Passphrase"), 354 _("Enter the passphrase you would like to use for encryption"), "", 355 "p", "obscured", "true", 356 "f", "passphrase_2", _("Passphrase again"), 357 _("Enter the passphrase again to confirm"), "", 358 "p", "obscured", "true", 359 360 "a", "ok", _("Accept and Set Passphrase"), "", "", 361 "p", "accelerator", "ESC", 362 363 NULL 364 ); 365 366 ds = dfui_dataset_new(); 367 dfui_dataset_celldata_add(ds, "passphrase_1", ""); 368 dfui_dataset_celldata_add(ds, "passphrase_2", ""); 369 dfui_form_dataset_add(f, ds); 370 371 while (!done) { 372 if (!dfui_be_present(a->c, f, &r)) 373 abort_backend(); 374 375 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) { 376 new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r)); 377 dfui_form_datasets_free(f); 378 dfui_form_dataset_add(f, new_ds); 379 380 /* 381 * Fetch form field values. 382 */ 383 384 passphrase_1 = dfui_dataset_get_value(new_ds, "passphrase_1"); 385 passphrase_2 = dfui_dataset_get_value(new_ds, "passphrase_2"); 386 387 if (strlen(passphrase_1) == 0 && strlen(passphrase_2) == 0) { 388 done = 0; 389 } else if (strcmp(passphrase_1, passphrase_2) == 0) { 390 /* 391 * Passphrases match, write it out. 392 */ 393 fd = open("/tmp/t1", O_RDWR | O_CREAT | O_TRUNC, 394 S_IRUSR); 395 if (fd != -1) { 396 write(fd, passphrase_1, strlen(passphrase_1)); 397 close(fd); 398 done = 1; 399 } else { 400 inform(a->c, _("write() error")); 401 done = 0; 402 } 403 } else { 404 /* 405 * Passphrases don't match, tell the user, 406 * let them try again. 407 */ 408 inform(a->c, _("The passphrases do not match.")); 409 done = 0; 410 } 411 } 412 413 dfui_response_free(r); 414 } 415 416 dfui_form_free(f); 417 } 418 419 /** LIVECD UTILITIES FUNCTIONS **/ 420 421 /* 422 * String returned by this function must be deallocated by the caller. 423 */ 424 char * 425 fn_select_file(const char *title, const char *desc, const char *help, const char *cancel, 426 const char *dir, const char *ext, const struct i_fn_args *a) 427 { 428 DIR *d; 429 struct dfui_form *f; 430 struct dfui_action *k; 431 struct dfui_response *r; 432 struct dirent *de; 433 char *s; 434 struct aura_dict *dict; 435 char *rk; 436 size_t rk_len; 437 438 f = dfui_form_create( 439 "select_file", 440 title, desc, help, 441 "p", "role", "menu", 442 NULL 443 ); 444 445 dict = aura_dict_new(1, AURA_DICT_SORTED_LIST); 446 d = opendir(dir); 447 while ((de = readdir(d)) != NULL) { 448 if (strcmp(de->d_name, ".") == 0 || 449 strcmp(de->d_name, "..") == 0 || 450 strstr(de->d_name, ext) == NULL) 451 continue; 452 aura_dict_store(dict, de->d_name, strlen(de->d_name) + 1, "", 1); 453 } 454 closedir(d); 455 456 aura_dict_rewind(dict); 457 while (!aura_dict_eof(dict)) { 458 aura_dict_get_current_key(dict, (void **)&rk, &rk_len), 459 dfui_form_action_add(f, rk, 460 dfui_info_new(rk, "", "")); 461 aura_dict_next(dict); 462 } 463 aura_dict_free(dict); 464 465 k = dfui_form_action_add(f, "cancel", 466 dfui_info_new(cancel, "", "")); 467 dfui_action_property_set(k, "accelerator", "ESC"); 468 469 if (!dfui_be_present(a->c, f, &r)) 470 abort_backend(); 471 472 s = aura_strdup(dfui_response_get_action_id(r)); 473 474 dfui_form_free(f); 475 dfui_response_free(r); 476 477 return(s); 478 } 479 480 void 481 fn_set_kbdmap(struct i_fn_args *a) 482 { 483 struct commands *cmds; 484 char *s; 485 char filename[256], keymapname[256]; 486 487 s = fn_select_file(_("Select Keyboard Map"), 488 _("Select a keyboard map appropriate to your keyboard layout."), 489 "", _("Return to Utilities Menu"), "/usr/share/syscons/keymaps", 490 ".kbd", a); 491 492 if (strcmp(s, "cancel") != 0) { 493 cmds = commands_new(); 494 command_add(cmds, "%s%s -l " 495 "/usr/share/syscons/keymaps/%s < /dev/ttyv0", 496 a->os_root, cmd_name(a, "KBDCONTROL"), 497 s); 498 if (commands_execute(a, cmds)) { 499 snprintf(filename, 256, "/usr/share/syscons/keymaps/%s", s); 500 snprintf(keymapname, 256, "%s", filename_noext(basename(filename))); 501 config_var_set(rc_conf, "keymap", keymapname); 502 } else { 503 inform(a->c, _("Keyboard map not successfully set.")); 504 } 505 commands_free(cmds); 506 } 507 508 free(s); 509 } 510 511 void 512 fn_set_vidfont(struct i_fn_args *a) 513 { 514 struct commands *cmds; 515 char *s; 516 char filename[256], variable[256], fontname[256]; 517 int by = 0; 518 519 520 s = fn_select_file(_("Select Console Font"), 521 _("Select a font appropriate to your video monitor and language."), 522 "", _("Return to Utilities Menu"), "/usr/share/syscons/fonts", 523 ".fnt", a); 524 525 if (strcmp(s, "cancel") != 0) { 526 cmds = commands_new(); 527 command_add(cmds, "%s%s -f " 528 "/usr/share/syscons/fonts/%s < /dev/ttyv0", 529 a->os_root, cmd_name(a, "VIDCONTROL"), 530 s); 531 if (commands_execute(a, cmds)) { 532 if (strstr(s, "8x16") != NULL) 533 by = 16; 534 else if (strstr(s, "8x14") != NULL) 535 by = 14; 536 else 537 by = 8; 538 539 snprintf(variable, 256, "font8x%d", by); 540 snprintf(filename, 256, "/usr/share/syscons/fonts/%s", s); 541 snprintf(fontname, 256, "%s", filename_noext(basename(filename))); 542 config_var_set(rc_conf, variable, fontname); 543 544 } else { 545 inform(a->c, _("Video font not successfully set.")); 546 } 547 commands_free(cmds); 548 } 549 550 free(s); 551 } 552 553 void 554 fn_set_scrnmap(struct i_fn_args *a) 555 { 556 struct commands *cmds; 557 char *s; 558 char filename[256], scrnmapname[256]; 559 560 s = fn_select_file(_("Select Screen Map"), 561 _("Select a mapping for translating characters as they appear " 562 "on your video console screen."), 563 "", _("Return to Utilities Menu"), "/usr/share/syscons/scrnmaps", 564 ".scm", a); 565 566 if (strcmp(s, "cancel") != 0) { 567 cmds = commands_new(); 568 command_add(cmds, "%s%s -l " 569 "/usr/share/syscons/scrnmaps/%s < /dev/ttyv0", 570 a->os_root, cmd_name(a, "VIDCONTROL"), 571 s); 572 if (commands_execute(a, cmds)) { 573 snprintf(filename, 256, "/usr/share/syscons/scrnmaps/%s", s); 574 snprintf(scrnmapname, 256, "%s", filename_noext(basename(filename))); 575 config_var_set(rc_conf, "scrnmap", scrnmapname); 576 } else { 577 inform(a->c, _("Video font not successfully set.")); 578 } 579 commands_free(cmds); 580 } 581 free(s); 582 } 583 584 void 585 fn_set_timezone(struct i_fn_args *a) 586 { 587 struct commands *cmds; 588 char *s = NULL; 589 char current_path[256], selection[256], temp[256]; 590 int found_file = 0; 591 int result; 592 593 result = dfui_be_present_dialog(a->c, _("Local or UTC (Greenwich Mean Time) clock"), 594 _("Yes|No"), 595 _("Is this machine's CMOS clock set to UTC?\n\n" 596 "If it is set to local time, or you don't know, please choose NO here!")); 597 if (result < 1) 598 abort_backend(); 599 600 cmds = commands_new(); 601 switch (result) { 602 case 1: 603 command_add(cmds, "%s%s -f %s%setc/wall_cmos_clock", 604 a->os_root, cmd_name(a, "RM"), 605 a->os_root, a->cfg_root); 606 break; 607 case 2: 608 command_add(cmds, "%s%s %s%setc/wall_cmos_clock", 609 a->os_root, cmd_name(a, "TOUCH"), 610 a->os_root, a->cfg_root); 611 break; 612 } 613 commands_execute(a, cmds); 614 615 snprintf(current_path, 256, "%s%susr/share/zoneinfo", 616 a->os_root, a->cfg_root); 617 while (!found_file) { 618 if (s != NULL) 619 free(s); 620 s = fn_select_file(_("Select Time Zone"), 621 _("Select a Time Zone appropriate to your physical location."), 622 "", _("Return to Utilities Menu"), current_path, 623 "", a); 624 if (is_dir("%s/%s", current_path, s)) { 625 snprintf(temp, 256, "%s/%s", current_path, s); 626 strlcpy(current_path, temp, 256); 627 } else { 628 if (is_file("%s/%s", current_path, s)) { 629 snprintf(selection, 256, "%s/%s", current_path, s); 630 found_file = 1; 631 } 632 if (strcmp(s, "cancel") == 0) { 633 strlcpy(selection, "cancel", 256); 634 found_file = 1; 635 } 636 } 637 } 638 free(s); 639 640 if (strcmp(selection, "cancel") != 0) { 641 command_add(cmds, "%s%s %s %s%setc/localtime", 642 a->os_root, cmd_name(a, "CP"), 643 selection, 644 a->os_root, a->cfg_root); 645 if (commands_execute(a, cmds)) { 646 inform(a->c, _("The Time Zone has been set to %s."), selection); 647 setenv("TZ", selection, 1); 648 tzset(); 649 } 650 } 651 commands_free(cmds); 652 } 653 654 void 655 fn_assign_datetime(struct i_fn_args *a) 656 { 657 struct commands *cmds; 658 struct dfui_dataset *ds, *new_ds; 659 struct dfui_form *f; 660 struct dfui_response *r; 661 struct tm *tp; 662 char temp[256]; 663 int year, month, dayofmonth, hour, minutes; 664 int valid = 1; 665 time_t now; 666 667 now = time(NULL); 668 tp = localtime(&now); 669 670 f = dfui_form_create( 671 "set_datetime", 672 _("Set Time/Date"), 673 _("Enter the date-time in your timezone."), 674 "", 675 676 "f", "year", _("Enter year"), 677 _("Enter the current year (e.g. `2004')"), "", 678 "f", "month", _("Month"), 679 _("Enter the current month (e.g. `07')"), "", 680 "f", "dayofmonth", "dayofmonth", 681 _("Enter the current day of month (e.g. `30')"), "", 682 "f", "hour", "hour", 683 _("Enter the current hour (e.g. `07')"), "", 684 "f", "minutes", "minutes", 685 _("Enter the current minutes (e.g. `59')"), "", 686 687 "a", "ok", _("OK"), "", "", 688 "a", "cancel", _("Cancel"), "", "", 689 "p", "accelerator", "ESC", 690 691 NULL 692 ); 693 694 ds = dfui_dataset_new(); 695 snprintf(temp, 256, "%i", (tp->tm_year+1900)); 696 dfui_dataset_celldata_add(ds, "year", temp); 697 snprintf(temp, 256, "%i", (tp->tm_mon+1)); 698 dfui_dataset_celldata_add(ds, "month", temp); 699 snprintf(temp, 256, "%i", tp->tm_mday); 700 dfui_dataset_celldata_add(ds, "dayofmonth", temp); 701 snprintf(temp, 256, "%i", tp->tm_hour); 702 dfui_dataset_celldata_add(ds, "hour", temp); 703 snprintf(temp, 256, "%i", tp->tm_min); 704 dfui_dataset_celldata_add(ds, "minutes", temp); 705 dfui_form_dataset_add(f, ds); 706 707 if (!dfui_be_present(a->c, f, &r)) 708 abort_backend(); 709 710 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) { 711 new_ds = dfui_response_dataset_get_first(r); 712 713 if ((year = atoi(dfui_dataset_get_value(new_ds, "year"))) <= 0) 714 valid = 0; 715 month = atoi(dfui_dataset_get_value(new_ds, "month")); 716 if (month < 1 || month > 12) 717 valid = 0; 718 dayofmonth = atoi(dfui_dataset_get_value(new_ds, "dayofmonth")); 719 if (dayofmonth < 1 || dayofmonth > 31) 720 valid = 0; 721 hour = atoi(dfui_dataset_get_value(new_ds, "hour")); 722 if (hour < 0 || hour > 23) 723 valid = 0; 724 minutes = atoi(dfui_dataset_get_value(new_ds, "minutes")); 725 if (minutes < 0 || minutes > 59) 726 valid = 0; 727 728 if (valid) { 729 cmds = commands_new(); 730 command_add(cmds, "%s%s -n %04d%02d%02d%02d%02d", 731 a->os_root, cmd_name(a, "DATE"), 732 year, month, dayofmonth, hour, minutes); 733 if (commands_execute(a, cmds)) { 734 inform(a->c, _("The date and time have been set.")); 735 } 736 commands_free(cmds); 737 } else { 738 inform(a->c, _("Please enter numbers within acceptable ranges " 739 "for year, month, day of month, hour, and minute.")); 740 } 741 } 742 } 743 744 void 745 fn_assign_hostname_domain(struct i_fn_args *a) 746 { 747 struct dfui_form *f; 748 struct dfui_response *r; 749 struct dfui_dataset *ds, *new_ds; 750 struct config_vars *resolv_conf; 751 const char *domain, *hostname; 752 char *fqdn; 753 754 f = dfui_form_create( 755 "set_hostname_domain", 756 _("Set Hostname/Domain"), 757 _("Please enter this machine's hostname and domain name."), 758 "", 759 760 "f", "hostname", _("Hostname"), 761 _("Enter the Hostname (e.g. `machine')"), "", 762 "f", "domain", _("Domain"), 763 _("Enter the Domain Name (e.g. `network.lan')"), "", 764 765 "a", "ok", _("OK"), "", "", 766 "a", "cancel", _("Cancel"), "", "", 767 "p", "accelerator", "ESC", 768 769 NULL 770 ); 771 772 ds = dfui_dataset_new(); 773 dfui_dataset_celldata_add(ds, "hostname", ""); 774 dfui_dataset_celldata_add(ds, "domain", ""); 775 dfui_form_dataset_add(f, ds); 776 777 if (!dfui_be_present(a->c, f, &r)) 778 abort_backend(); 779 780 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) { 781 new_ds = dfui_response_dataset_get_first(r); 782 783 hostname = dfui_dataset_get_value(new_ds, "hostname"); 784 domain = dfui_dataset_get_value(new_ds, "domain"); 785 if (strlen(domain) == 0) 786 asprintf(&fqdn, "%s", hostname); 787 else 788 asprintf(&fqdn, "%s.%s", hostname, domain); 789 790 resolv_conf = config_vars_new(); 791 792 config_var_set(rc_conf, "hostname", fqdn); 793 config_var_set(resolv_conf, "search", domain); 794 config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV, 795 "%s%setc/resolv.conf", a->os_root, a->cfg_root); 796 797 config_vars_free(resolv_conf); 798 799 free(fqdn); 800 } 801 802 dfui_form_free(f); 803 dfui_response_free(r); 804 } 805 806 void 807 fn_assign_ip(struct i_fn_args *a) 808 { 809 FILE *p; 810 struct commands *cmds; 811 struct command *cmd; 812 struct config_vars *resolv_conf; 813 struct dfui_dataset *ds, *new_ds; 814 struct dfui_form *f; 815 struct dfui_action *k; 816 struct dfui_response *r; 817 const char *domain, *hostname; 818 const char *interface_ip, *interface_netmask, *defaultrouter, *dns_resolver; 819 char *string, *string1; 820 char *word; 821 char interface[256]; 822 char line[256]; 823 int write_config = 0; 824 825 /* 826 * Get interface list. 827 */ 828 p = popen("/sbin/ifconfig -l", "r"); 829 /* XXX it's possible (though extremely unlikely) this will fail. */ 830 while (fgets(line, 255, p) != NULL) 831 line[strlen(line) - 1] = '\0'; 832 833 pclose(p); 834 835 f = dfui_form_create( 836 "assign_ip", 837 _("Assign IP Address"), 838 _("Please select which interface you would like to configure:"), 839 "", 840 "p", "role", "menu", 841 NULL 842 ); 843 844 /* Loop through array. */ 845 word = strtok(line, " \t"); 846 while (word != NULL) { 847 dfui_form_action_add(f, word, 848 dfui_info_new(word, "", "")); 849 word = strtok(NULL, " "); 850 } 851 852 k = dfui_form_action_add(f, "cancel", 853 dfui_info_new("Cancel", "", "")); 854 dfui_action_property_set(k, "accelerator", "ESC"); 855 856 if (!dfui_be_present(a->c, f, &r)) 857 abort_backend(); 858 859 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { 860 dfui_form_free(f); 861 dfui_response_free(r); 862 return; 863 } 864 865 strlcpy(interface, dfui_response_get_action_id(r), 256); 866 867 resolv_conf = config_vars_new(); 868 869 switch (dfui_be_present_dialog(a->c, _("Use DHCP?"), 870 _("Use DHCP|Configure Manually"), 871 _("DHCP allows the interface to automatically obtain " 872 "an IP address from a nearby DHCP server.\n\n" 873 "Would you like to enable DHCP for %s?"), interface)) { 874 case 1: 875 asprintf(&string, "ifconfig_%s", interface); 876 877 cmds = commands_new(); 878 cmd = command_add(cmds, "%s%s dhclient", 879 a->os_root, cmd_name(a, "KILLALL")); 880 command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE); 881 command_add(cmds, "%s%s %s", 882 a->os_root, cmd_name(a, "DHCLIENT"), 883 interface); 884 if (commands_execute(a, cmds)) { 885 /* XXX sleep(3); */ 886 show_ifconfig(a->c, interface); 887 write_config = 1; 888 } else { 889 switch (dfui_be_present_dialog(a->c, _("DHCP Failure"), 890 _("Yes|No"), 891 _("Warning: could not enable dhclient for %s.\n\n" 892 "Write the corresponding settings to rc.conf " 893 "anyway?"), interface)) { 894 case 1: 895 write_config = 1; 896 break; 897 case 2: 898 write_config = 0; 899 break; 900 default: 901 abort_backend(); 902 } 903 } 904 commands_free(cmds); 905 config_var_set(rc_conf, string, "DHCP"); 906 free(string); 907 break; 908 case 2: 909 dfui_form_free(f); 910 dfui_response_free(r); 911 f = dfui_form_create( 912 "assign_ip", 913 _("Assign IP Address"), 914 _("Configuring Interface:"), 915 "", 916 917 "f", "interface_ip", _("IP Address"), 918 _("Enter the IP Address you would like to use"), "", 919 "f", "interface_netmask", _("Netmask"), 920 _("Enter the netmask of the IP address"), "", 921 "f", "defaultrouter", _("Default Router"), 922 _("Enter the IP address of the default router"), "", 923 "f", "dns_resolver", _("Primary DNS Server"), 924 _("Enter the IP address of primary DNS Server"), "", 925 "f", "hostname", _("Hostname"), 926 _("Enter the Hostname"), "", 927 "f", "domain", _("Domain"), 928 _("Enter the Domain Name"), "", 929 930 "a", "ok", _("Configure Interface"), 931 "", "", 932 "a", "cancel", _("Return to Utilities Menu"), 933 "", "", 934 "p", "accelerator", "ESC", 935 936 NULL 937 ); 938 939 ds = dfui_dataset_new(); 940 dfui_dataset_celldata_add(ds, "interface_netmask", ""); 941 dfui_dataset_celldata_add(ds, "defaultrouter", ""); 942 dfui_dataset_celldata_add(ds, "dns_resolver", ""); 943 dfui_dataset_celldata_add(ds, "hostname", ""); 944 dfui_dataset_celldata_add(ds, "domain", ""); 945 dfui_dataset_celldata_add(ds, "interface_ip", ""); 946 dfui_form_dataset_add(f, ds); 947 948 if (!dfui_be_present(a->c, f, &r)) 949 abort_backend(); 950 951 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) { 952 new_ds = dfui_response_dataset_get_first(r); 953 954 interface_ip = dfui_dataset_get_value( 955 new_ds, "interface_ip"); 956 interface_netmask = dfui_dataset_get_value( 957 new_ds, "interface_netmask"); 958 defaultrouter = dfui_dataset_get_value( 959 new_ds, "defaultrouter"); 960 dns_resolver = dfui_dataset_get_value( 961 new_ds, "dns_resolver"); 962 hostname = dfui_dataset_get_value( 963 new_ds, "hostname"); 964 domain = dfui_dataset_get_value( 965 new_ds, "domain"); 966 967 asprintf(&string, "ifconfig_%s", interface); 968 asprintf(&string1, "inet %s netmask %s", 969 interface_ip, interface_netmask); 970 971 cmds = commands_new(); 972 command_add(cmds, "%s%s %s %s netmask %s", 973 a->os_root, cmd_name(a, "IFCONFIG"), 974 interface, interface_ip, interface_netmask); 975 command_add(cmds, "%s%s add default %s", 976 a->os_root, cmd_name(a, "ROUTE"), 977 defaultrouter); 978 979 if (commands_execute(a, cmds)) { 980 /* XXX sleep(3); */ 981 show_ifconfig(a->c, interface); 982 write_config = 1; 983 } else { 984 switch (dfui_be_present_dialog(a->c, 985 _("ifconfig Failure"), 986 _("Yes|No"), 987 _("Warning: could not assign IP address " 988 "or default gateway.\n\n" 989 "Write the corresponding settings to " 990 "rc.conf anyway?"))) { 991 case 1: 992 write_config = 1; 993 break; 994 case 2: 995 write_config = 0; 996 break; 997 default: 998 abort_backend(); 999 } 1000 } 1001 commands_free(cmds); 1002 1003 config_var_set(rc_conf, string, string1); 1004 config_var_set(rc_conf, "defaultrouter", defaultrouter); 1005 1006 free(string); 1007 free(string1); 1008 1009 asprintf(&string, "%s.%s", hostname, domain); 1010 config_var_set(rc_conf, "hostname", string); 1011 free(string); 1012 1013 config_var_set(resolv_conf, "search", domain); 1014 config_var_set(resolv_conf, "nameserver", dns_resolver); 1015 } 1016 break; 1017 default: 1018 abort_backend(); 1019 } 1020 1021 if (write_config) { 1022 /* 1023 * Save out changes to /etc/rc.conf and /etc/resolv.conf. 1024 */ 1025 config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV, 1026 "%s%setc/resolv.conf", a->os_root, a->cfg_root); 1027 } 1028 1029 config_vars_free(resolv_conf); 1030 1031 dfui_form_free(f); 1032 dfui_response_free(r); 1033 } 1034 1035 static const char * 1036 yes_to_y(const char *value) 1037 { 1038 return(strcasecmp(value, "YES") == 0 ? "Y" : "N"); 1039 } 1040 1041 void 1042 fn_select_services(struct i_fn_args *a) 1043 { 1044 struct dfui_dataset *ds; 1045 struct dfui_form *f; 1046 struct dfui_response *r; 1047 1048 if (!config_vars_read(a, rc_conf, CONFIG_TYPE_SH, "%s%setc/rc.conf", 1049 a->os_root, a->cfg_root)) { 1050 inform(a->c, _("Couldn't read %s%setc/rc.conf."), 1051 a->os_root, a->cfg_root); 1052 a->result = 0; 1053 return; 1054 } 1055 1056 f = dfui_form_create( 1057 "select_services", 1058 _("Select Services"), 1059 _("Please select which services you would like " 1060 "started at boot time."), 1061 "", 1062 1063 "f", "syslogd", "syslogd", 1064 _("System Logging Daemon"), "", 1065 "p", "control", "checkbox", 1066 "f", "inetd", "inetd", 1067 _("Internet Super-Server"), "", 1068 "p", "control", "checkbox", 1069 "f", "named", "named", 1070 _("BIND Name Server"), "", 1071 "p", "control", "checkbox", 1072 "f", "ntpd", "ntpd", 1073 _("Network Time Protocol Daemon"), "", 1074 "p", "control", "checkbox", 1075 "f", "sshd", "sshd", 1076 _("Secure Shell Daemon"), "", 1077 "p", "control", "checkbox", 1078 1079 "a", "ok", _("Enable/Disable Services"), 1080 "", "", 1081 "a", "cancel", _("Return to Utilities Menu"), 1082 "", "", 1083 "p", "accelerator", "ESC", 1084 1085 NULL 1086 ); 1087 1088 ds = dfui_dataset_new(); 1089 dfui_dataset_celldata_add(ds, "syslogd", 1090 yes_to_y(config_var_get(rc_conf, "syslogd_enable"))); 1091 dfui_dataset_celldata_add(ds, "inetd", 1092 yes_to_y(config_var_get(rc_conf, "inetd_enable"))); 1093 dfui_dataset_celldata_add(ds, "named", 1094 yes_to_y(config_var_get(rc_conf, "named_enable"))); 1095 dfui_dataset_celldata_add(ds, "ntpd", 1096 yes_to_y(config_var_get(rc_conf, "ntpd_enable"))); 1097 dfui_dataset_celldata_add(ds, "sshd", 1098 yes_to_y(config_var_get(rc_conf, "sshd_enable"))); 1099 dfui_form_dataset_add(f, ds); 1100 1101 if (!dfui_be_present(a->c, f, &r)) 1102 abort_backend(); 1103 1104 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { 1105 dfui_form_free(f); 1106 dfui_response_free(r); 1107 return; 1108 } 1109 1110 dfui_form_free(f); 1111 dfui_response_free(r); 1112 } 1113 1114 /*** NON-fn_ FUNCTIONS ***/ 1115 1116 /* 1117 * Uses ss->selected_{disk,slice} as the target system. 1118 * 1119 * XXX We now assume that the root mount has enough of the topology 1120 * to handle any configuration actions. 1121 */ 1122 int 1123 mount_target_system(struct i_fn_args *a) 1124 { 1125 FILE *crypttab, *fstab; 1126 struct commands *cmds; 1127 struct command *cmd; 1128 struct subpartition *a_subpart; 1129 struct subpartition *d_subpart; 1130 char name[256], device[256]; 1131 char *filename, line[256]; 1132 char *word; 1133 1134 /* 1135 * Mount subpartitions from this installation if they are 1136 * not already mounted. Tricky, as we need to honour the 1137 * installation's loader.conf and fstab. 1138 */ 1139 cmds = commands_new(); 1140 1141 /* 1142 * First, unmount anything already mounted on /mnt. 1143 */ 1144 unmount_all_under(a, cmds, "%smnt", a->os_root); 1145 1146 /* 1147 * Reset and clear out subpartitions so that system 1148 * can make a "dummy" subpart. 1149 */ 1150 subpartitions_free(storage_get_selected_slice(a->s)); 1151 1152 /* 1153 * Create a temporary dummy subpartition - that we 1154 * assume exists 1155 */ 1156 a_subpart = subpartition_new_ufs(storage_get_selected_slice(a->s), 1157 "/dummy", 0, 0, 0, 0, 0, 0); 1158 subpartition_new_ufs(storage_get_selected_slice(a->s), 1159 "swap", 0, 0, 0, 0, 0, 0); 1160 d_subpart = subpartition_new_ufs(storage_get_selected_slice(a->s), 1161 "/dummy", 0, 0, 0, 0, 0, 0); 1162 1163 /* 1164 * Mount the target's / and read its /etc/fstab. 1165 * 1166 * XXX NEEDS TO BE REWRITTEN XXX 1167 */ 1168 { 1169 command_add(cmds, "%s%s /dev/%s %sboot", 1170 a->os_root, cmd_name(a, "MOUNT"), 1171 subpartition_get_device_name(a_subpart), 1172 a->os_root); 1173 cmd = command_add(cmds, 1174 "%s%s -f %st2;" 1175 "%s%s \"^vfs\\.root\\.realroot=\" %sboot/loader.conf >%st2", 1176 a->os_root, cmd_name(a, "RM"), a->tmp, 1177 a->os_root, cmd_name(a, "GREP"), 1178 a->os_root, a->tmp); 1179 command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE); 1180 } 1181 if (!commands_execute(a, cmds)) { 1182 commands_free(cmds); 1183 return(0); 1184 } 1185 commands_free(cmds); 1186 cmds = commands_new(); 1187 1188 /* 1189 * XXX NEEDS TO BE REWRITTEN XXX 1190 */ 1191 { 1192 struct stat sb = { .st_size = 0 }; 1193 const char *fsname; 1194 const char *mountid; 1195 1196 switch (use_hammer) { 1197 case 1: 1198 fsname = "hammer"; 1199 mountid = "MOUNT_HAMMER"; 1200 break; 1201 case 2: 1202 fsname = "hammer2"; 1203 mountid = "MOUNT_HAMMER2"; 1204 break; 1205 case 0: 1206 default: 1207 fsname = "ufs"; 1208 mountid = "MOUNT"; 1209 break; 1210 } 1211 1212 stat("/tmp/t2", &sb); 1213 if (sb.st_size > 0) { 1214 command_add(cmds, "%s%s %sboot", 1215 a->os_root, cmd_name(a, "UMOUNT"), 1216 a->os_root); 1217 fn_get_passphrase(a); 1218 command_add(cmds, 1219 "%s%s -d /tmp/t1 luksOpen /dev/`%s%s \"^vfs\\.root\\.realroot=\" %st2 |" 1220 "%s%s -F%s: '{print $2;}' |" 1221 "%s%s -F: '{print $1;}'` %s", 1222 a->os_root, cmd_name(a, "CRYPTSETUP"), 1223 a->os_root, cmd_name(a, "GREP"), 1224 a->tmp, 1225 a->os_root, cmd_name(a, "AWK"), 1226 fsname, 1227 a->os_root, cmd_name(a, "AWK"), 1228 subpartition_get_mapper_name(d_subpart, -1)); 1229 command_add(cmds, 1230 "%s%s %s %s%s", 1231 a->os_root, 1232 cmd_name(a, mountid), 1233 subpartition_get_mapper_name(d_subpart, 1), 1234 a->os_root, a->cfg_root); 1235 } else { 1236 command_add(cmds, 1237 "%s%s /dev/`%s%s \"^vfs\\.root\\.mountfrom\" %sboot/loader.conf |" 1238 "%s%s -F%s: '{print $2;}' |" 1239 "%s%s 's/\"//'` %s%s", 1240 a->os_root, 1241 cmd_name(a, mountid), 1242 a->os_root, cmd_name(a, "GREP"), 1243 a->os_root, 1244 a->os_root, cmd_name(a, "AWK"), 1245 fsname, 1246 a->os_root, cmd_name(a, "SED"), 1247 a->os_root, a->cfg_root); 1248 command_add(cmds, "%s%s %sboot", 1249 a->os_root, cmd_name(a, "UMOUNT"), 1250 a->os_root); 1251 } 1252 } 1253 if (!commands_execute(a, cmds)) { 1254 commands_free(cmds); 1255 return(0); 1256 } 1257 commands_free(cmds); 1258 cmds = commands_new(); 1259 1260 /* 1261 * Get rid of the dummy subpartition. 1262 */ 1263 subpartitions_free(storage_get_selected_slice(a->s)); 1264 1265 /* 1266 * See if an /etc/crypttab exists. 1267 * 1268 * Scan and open the related mappings (currently not used since 1269 * we removed the additional mounts from the fstab scan, but we 1270 * might put those back in at a future date so leave this in for 1271 * now). 1272 */ 1273 asprintf(&filename, "%s%s/etc/crypttab", a->os_root, a->cfg_root); 1274 crypttab = fopen(filename, "r"); 1275 free(filename); 1276 if (crypttab != NULL) { 1277 while (fgets(line, 256, crypttab) != NULL) { 1278 /* 1279 * Parse the crypttab line. 1280 */ 1281 if (first_non_space_char_is(line, '#')) 1282 continue; 1283 if ((word = strtok(line, " \t")) == NULL) 1284 continue; 1285 strlcpy(name, word, 256); 1286 1287 /* don't mount encrypted swap */ 1288 if (strcmp(name, "swap") == 0) 1289 continue; 1290 /* encrypted root already mounted */ 1291 if (strcmp(name, subpartition_get_mapper_name(d_subpart, -1)) == 0) 1292 continue; 1293 1294 if ((word = strtok(NULL, " \t")) == NULL) 1295 continue; 1296 strlcpy(device, word, 256); 1297 1298 command_add(cmds, 1299 "%s%s -d /tmp/t1 luksOpen %s %s", 1300 a->os_root, cmd_name(a, "CRYPTSETUP"), 1301 device, name); 1302 1303 continue; 1304 } 1305 fclose(crypttab); 1306 } 1307 if (!commands_execute(a, cmds)) { 1308 commands_free(cmds); 1309 return(0); 1310 } 1311 commands_free(cmds); 1312 1313 /* 1314 * (current we do not mount the other partitions, everything needed 1315 * for system configuration should be on the already-mounted root). 1316 */ 1317 asprintf(&filename, "%s%s/etc/fstab", a->os_root, a->cfg_root); 1318 fstab = fopen(filename, "r"); 1319 free(filename); 1320 if (fstab == NULL) { 1321 inform(a->c, _("Filesystem table on installed system could not be read.")); 1322 cmds = commands_new(); 1323 command_add(cmds, "%s%s %s%s", 1324 a->os_root, cmd_name(a, "UMOUNT"), 1325 a->os_root, a->cfg_root); 1326 if (!commands_execute(a, cmds)) { 1327 inform(a->c, _("Warning: Installed system was not properly unmounted.")); 1328 } 1329 commands_free(cmds); 1330 return(0); 1331 } 1332 fclose(fstab); 1333 1334 return 1; 1335 } 1336