]>
Commit | Line | Data |
---|---|---|
a79082a0 DM |
1 | /// Helper to run tape commands as root. Currently only required |
2 | /// to read and set the encryption key. | |
b27c3282 DM |
3 | /// |
4 | /// This command can use STDIN as tape device handle. | |
5 | ||
6 | use std::fs::File; | |
7 | use std::os::unix::io::{AsRawFd, FromRawFd}; | |
8 | ||
8a0046f5 | 9 | use anyhow::{bail, Error}; |
2d50a619 | 10 | use serde_json::Value; |
b27c3282 | 11 | |
6ef1b649 WB |
12 | use proxmox_router::{cli::*, RpcEnvironment}; |
13 | use proxmox_schema::api; | |
14 | use proxmox_uuid::Uuid; | |
b27c3282 | 15 | |
1ce8e905 DM |
16 | use pbs_api_types::{ |
17 | Fingerprint, LTO_DRIVE_PATH_SCHEMA, DRIVE_NAME_SCHEMA, TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA, | |
18 | MEDIA_SET_UUID_SCHEMA, LtoTapeDrive, | |
19 | }; | |
b2065dc7 | 20 | |
048b43af DM |
21 | use pbs_tape::linux_list_drives::{open_lto_tape_device, check_tape_is_lto_tape_device}; |
22 | ||
b27c3282 | 23 | use proxmox_backup::{ |
b27c3282 | 24 | tape::{ |
37796ff7 DM |
25 | drive::{ |
26 | TapeDriver, | |
a79082a0 | 27 | LtoTapeHandle, |
1ce8e905 | 28 | open_lto_tape_drive, |
b27c3282 DM |
29 | }, |
30 | }, | |
31 | }; | |
32 | ||
a79082a0 | 33 | fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> { |
2d50a619 DM |
34 | |
35 | let handle = if let Some(name) = param["drive"].as_str() { | |
1ce8e905 | 36 | let (config, _digest) = pbs_config::drive::config()?; |
9a37bd6c | 37 | let drive: LtoTapeDrive = config.lookup("lto", name)?; |
2d50a619 | 38 | eprintln!("using device {}", drive.path); |
1ce8e905 | 39 | open_lto_tape_drive(&drive)? |
2d50a619 DM |
40 | } else if let Some(device) = param["device"].as_str() { |
41 | eprintln!("using device {}", device); | |
9a37bd6c | 42 | LtoTapeHandle::new(open_lto_tape_device(device)?)? |
2d50a619 DM |
43 | } else if let Some(true) = param["stdin"].as_bool() { |
44 | eprintln!("using stdin"); | |
b27c3282 DM |
45 | let fd = std::io::stdin().as_raw_fd(); |
46 | let file = unsafe { File::from_raw_fd(fd) }; | |
a79082a0 DM |
47 | check_tape_is_lto_tape_device(&file)?; |
48 | LtoTapeHandle::new(file)? | |
ea368a06 | 49 | } else if let Ok(name) = std::env::var("PROXMOX_TAPE_DRIVE") { |
1ce8e905 | 50 | let (config, _digest) = pbs_config::drive::config()?; |
a79082a0 | 51 | let drive: LtoTapeDrive = config.lookup("lto", &name)?; |
2d50a619 | 52 | eprintln!("using device {}", drive.path); |
1ce8e905 | 53 | open_lto_tape_drive(&drive)? |
2d50a619 | 54 | } else { |
1ce8e905 | 55 | let (config, _digest) = pbs_config::drive::config()?; |
2d50a619 DM |
56 | |
57 | let mut drive_names = Vec::new(); | |
58 | for (name, (section_type, _)) in config.sections.iter() { | |
a79082a0 | 59 | if section_type != "lto" { continue; } |
2d50a619 DM |
60 | drive_names.push(name); |
61 | } | |
62 | ||
63 | if drive_names.len() == 1 { | |
64 | let name = drive_names[0]; | |
9a37bd6c | 65 | let drive: LtoTapeDrive = config.lookup("lto", name)?; |
2d50a619 | 66 | eprintln!("using device {}", drive.path); |
1ce8e905 | 67 | open_lto_tape_drive(&drive)? |
2d50a619 DM |
68 | } else { |
69 | bail!("no drive/device specified"); | |
70 | } | |
b27c3282 | 71 | }; |
2d50a619 DM |
72 | |
73 | Ok(handle) | |
b27c3282 DM |
74 | } |
75 | ||
d5a48b5c DM |
76 | #[api( |
77 | input: { | |
78 | properties: { | |
79 | fingerprint: { | |
80 | schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA, | |
81 | optional: true, | |
82 | }, | |
2b191385 DM |
83 | uuid: { |
84 | schema: MEDIA_SET_UUID_SCHEMA, | |
85 | optional: true, | |
86 | }, | |
d5a48b5c DM |
87 | drive: { |
88 | schema: DRIVE_NAME_SCHEMA, | |
89 | optional: true, | |
90 | }, | |
91 | device: { | |
a79082a0 | 92 | schema: LTO_DRIVE_PATH_SCHEMA, |
d5a48b5c DM |
93 | optional: true, |
94 | }, | |
95 | stdin: { | |
96 | description: "Use standard input as device handle.", | |
97 | type: bool, | |
98 | optional: true, | |
99 | }, | |
100 | }, | |
101 | }, | |
102 | )] | |
103 | /// Set or clear encryption key | |
104 | fn set_encryption( | |
105 | fingerprint: Option<Fingerprint>, | |
2b191385 | 106 | uuid: Option<Uuid>, |
d5a48b5c DM |
107 | param: Value, |
108 | ) -> Result<(), Error> { | |
109 | ||
6ef1b649 | 110 | let result = proxmox_lang::try_block!({ |
d5a48b5c DM |
111 | let mut handle = get_tape_handle(¶m)?; |
112 | ||
2b191385 DM |
113 | match (fingerprint, uuid) { |
114 | (Some(fingerprint), Some(uuid)) => { | |
115 | handle.set_encryption(Some((fingerprint, uuid)))?; | |
116 | } | |
117 | (Some(_), None) => { | |
118 | bail!("missing media set uuid"); | |
119 | } | |
120 | (None, _) => { | |
121 | handle.set_encryption(None)?; | |
122 | } | |
123 | } | |
124 | ||
d5a48b5c DM |
125 | Ok(()) |
126 | }).map_err(|err: Error| err.to_string()); | |
127 | ||
128 | println!("{}", serde_json::to_string_pretty(&result)?); | |
129 | ||
130 | Ok(()) | |
131 | } | |
132 | ||
b27c3282 DM |
133 | fn main() -> Result<(), Error> { |
134 | ||
135 | // check if we are user root or backup | |
21211748 DM |
136 | let backup_uid = pbs_config::backup_user()?.uid; |
137 | let backup_gid = pbs_config::backup_group()?.gid; | |
b27c3282 DM |
138 | let running_uid = nix::unistd::Uid::current(); |
139 | let running_gid = nix::unistd::Gid::current(); | |
140 | ||
141 | let effective_uid = nix::unistd::Uid::effective(); | |
142 | if !effective_uid.is_root() { | |
143 | bail!("this program needs to be run with setuid root"); | |
144 | } | |
145 | ||
6334bdc1 FG |
146 | if !running_uid.is_root() && (running_uid != backup_uid || running_gid != backup_gid) { |
147 | bail!( | |
148 | "Not running as backup user or group (got uid {} gid {})", | |
149 | running_uid, running_gid, | |
150 | ); | |
b27c3282 DM |
151 | } |
152 | ||
153 | let cmd_def = CliCommandMap::new() | |
d5a48b5c DM |
154 | .insert( |
155 | "encryption", | |
156 | CliCommand::new(&API_METHOD_SET_ENCRYPTION) | |
157 | ) | |
b27c3282 DM |
158 | ; |
159 | ||
160 | let mut rpcenv = CliEnvironment::new(); | |
161 | rpcenv.set_auth_id(Some(String::from("root@pam"))); | |
162 | ||
163 | run_cli_command(cmd_def, rpcenv, None); | |
164 | ||
165 | Ok(()) | |
166 | } |