|
26 | 26 | from os import readlink
|
27 | 27 | from os import getpid, getppid
|
28 | 28 | from typing import Union
|
29 |
| -from urllib.parse import urlparse |
| 29 | +from urllib.parse import urlparse, uses_relative |
30 | 30 | from passlib.hosts import linux_context
|
31 | 31 | from errno import ENOSPC
|
32 | 32 |
|
|
37 | 37 | from vyos.system import disk, grub, image, compat, raid, SYSTEM_CFG_VER
|
38 | 38 | from vyos.template import render
|
39 | 39 | from vyos.utils.io import ask_input, ask_yes_no, select_entry
|
40 |
| -from vyos.utils.file import chmod_2775 |
| 40 | +from vyos.utils.file import chmod, chmod_2775 |
41 | 41 | from vyos.utils.process import cmd, run, rc_cmd
|
42 | 42 | from vyos.version import get_version_data
|
43 | 43 |
|
@@ -318,6 +318,30 @@ def copy_preserve_owner(src: str, dst: str, *, follow_symlinks=True):
|
318 | 318 | chown(dst, user=st.st_uid)
|
319 | 319 |
|
320 | 320 |
|
| 321 | +def copy_all_matching(src: str, dst: str, *, follow_symlinks=True) -> None: |
| 322 | + """Copies all that match the given pattern files from to the target |
| 323 | +
|
| 324 | + :param src: Path to the file or files to copy; can be a pattern |
| 325 | + :param dst: destination path; |
| 326 | + :param follow_symlinks: If False, symlinks won't be followed |
| 327 | + """ |
| 328 | + og_files: list[str] = glob(src) |
| 329 | + for og in og_files: |
| 330 | + if not Path(og).is_file(): |
| 331 | + return |
| 332 | + # Create directory if needed and ensure proper ownership |
| 333 | + if Path(dst).is_dir(): |
| 334 | + st = Path(src).parent.stat() |
| 335 | + Path(dst).mkdir(parents=True, exist_ok=True) |
| 336 | + chmod(Path(dst), st.st_mode) |
| 337 | + chown(Path(dst), user=st.st_uid, group=st.st_gid) |
| 338 | + dst = Path(dst).joinpath(Path(og).name) |
| 339 | + |
| 340 | + st = Path(og).stat() |
| 341 | + copy(og, dst, follow_symlinks=follow_symlinks) |
| 342 | + chown(dst, user=st.st_uid, group=st.st_gid) |
| 343 | + |
| 344 | + |
321 | 345 | def copy_previous_installation_data(target_dir: str) -> None:
|
322 | 346 | if Path('/mnt/config').exists():
|
323 | 347 | copytree('/mnt/config', f'{target_dir}/opt/vyatta/etc/config',
|
@@ -634,6 +658,19 @@ def copy_ssh_host_keys() -> bool:
|
634 | 658 | return False
|
635 | 659 |
|
636 | 660 |
|
| 661 | +def copy_ssh_hosts_fingerprints() -> bool: |
| 662 | + """Ask user to copy known SSH hosts (fingerprints) |
| 663 | +
|
| 664 | + Returns: |
| 665 | + bool: user's decision |
| 666 | + """ |
| 667 | + question = 'Would you like to save the SSH known hosts (fingerprints) '\ |
| 668 | + 'from your current configuration?' |
| 669 | + if ask_yes_no(question, default=True): |
| 670 | + return True |
| 671 | + return False |
| 672 | + |
| 673 | + |
637 | 674 | def console_hint() -> str:
|
638 | 675 | pid = getppid() if 'SUDO_USER' in environ else getpid()
|
639 | 676 | try:
|
@@ -995,13 +1032,60 @@ def add_image(image_path: str, vrf: str = None, username: str = '',
|
995 | 1032 | chmod_2775(target_config_dir)
|
996 | 1033 | Path(f'{target_config_dir}/.vyatta_config').touch()
|
997 | 1034 |
|
998 |
| - target_ssh_dir: str = f'{root_dir}/boot/{image_name}/rw/etc/ssh/' |
| 1035 | + src_ssh_etc: str = '/etc/ssh/known_hosts' |
| 1036 | + src_ssh_root: str = '/root/.ssh' |
| 1037 | + target_ssh_etc: str = f'{root_dir}/boot/{image_name}/rw/etc/ssh/' |
| 1038 | + target_ssh_root: str = f'{root_dir}/boot/{image_name}/rw/root/.ssh/' |
| 1039 | + |
999 | 1040 | if no_prompt or copy_ssh_host_keys():
|
1000 | 1041 | print('Copying SSH host keys')
|
1001 |
| - Path(target_ssh_dir).mkdir(parents=True) |
1002 |
| - host_keys: list[str] = glob('/etc/ssh/ssh_host*') |
1003 |
| - for host_key in host_keys: |
1004 |
| - copy(host_key, target_ssh_dir) |
| 1042 | + copy_all_matching('/etc/ssh/ssh_host*', target_ssh_etc) |
| 1043 | + # Path(target_ssh_etc).mkdir(parents=True) |
| 1044 | + # host_keys: list[str] = glob('/etc/ssh/ssh_host*') |
| 1045 | + # for host_key in host_keys: |
| 1046 | + # copy(host_key, target_ssh_etc) |
| 1047 | + |
| 1048 | + if no_prompt or copy_ssh_hosts_fingerprints(): |
| 1049 | + if not any([ |
| 1050 | + Path(src_ssh_etc).exists(), |
| 1051 | + Path(src_ssh_root).exists(), |
| 1052 | + ]): |
| 1053 | + print('No SSH host fingerprints are found') |
| 1054 | + else: |
| 1055 | + print('Copying known SSH hosts (fingerprints)') |
| 1056 | + if Path(src_ssh_etc).exists(): |
| 1057 | + copy_all_matching( |
| 1058 | + src=src_ssh_etc, |
| 1059 | + dst=target_ssh_etc |
| 1060 | + ) |
| 1061 | + |
| 1062 | + if Path(src_ssh_root).exists(): |
| 1063 | + copy_all_matching( |
| 1064 | + src=src_ssh_root, |
| 1065 | + dst=target_ssh_root |
| 1066 | + ) |
| 1067 | + # print('Copying known SSH hosts (fingerprints)') |
| 1068 | + # # Copy global fingerprints |
| 1069 | + # copy_all_matching( |
| 1070 | + # src='/etc/ssh/known_hosts*', |
| 1071 | + # dst=target_ssh_etc, |
| 1072 | + # follow_symlinks=False |
| 1073 | + # ) |
| 1074 | + # # Copy saved fingerprints of each user |
| 1075 | + # homedirs: list[str] = glob('/home/*') |
| 1076 | + # for user_dir in homedirs: |
| 1077 | + # # target = f'{root_dir}/boot/{image_name}/rw{user_dir}/.ssh/' |
| 1078 | + # # copy_all_matching( |
| 1079 | + # # src=f'{user_dir}/.ssh/known_hosts*', |
| 1080 | + # # dst=target, |
| 1081 | + # # follow_symlinks=False |
| 1082 | + # # ) |
| 1083 | + # # Copy root fingerprints |
| 1084 | + # copy_all_matching( |
| 1085 | + # src='/root/.ssh/known_hosts*', |
| 1086 | + # dst=target_ssh_root, |
| 1087 | + # follow_symlinks=False |
| 1088 | + # ) |
1005 | 1089 |
|
1006 | 1090 | # copy system image and kernel files
|
1007 | 1091 | print('Copying system image files')
|
|
0 commit comments