xref: /DragonOS/user/apps/user-manage/src/executor/executor.rs (revision 03746da3d9f3ea616cecdb6e581414002075f866)
1*03746da3SJomo use crate::{
2*03746da3SJomo     check::info::{GAddInfo, GDelInfo, GModInfo, PasswdInfo, UAddInfo, UDelInfo, UModInfo},
3*03746da3SJomo     error::error::{ErrorHandler, ExitStatus},
4*03746da3SJomo };
5*03746da3SJomo use lazy_static::lazy_static;
6*03746da3SJomo use std::{
7*03746da3SJomo     fs::{self, File, OpenOptions},
8*03746da3SJomo     io::{Read, Seek, Write},
9*03746da3SJomo     sync::Mutex,
10*03746da3SJomo };
11*03746da3SJomo 
12*03746da3SJomo lazy_static! {
13*03746da3SJomo     static ref GLOBAL_FILE: Mutex<GlobalFile> = Mutex::new(GlobalFile::new());
14*03746da3SJomo }
15*03746da3SJomo 
16*03746da3SJomo #[derive(Debug)]
17*03746da3SJomo pub struct GlobalFile {
18*03746da3SJomo     passwd_file: File,
19*03746da3SJomo     shadow_file: File,
20*03746da3SJomo     group_file: File,
21*03746da3SJomo     gshadow_file: File,
22*03746da3SJomo }
23*03746da3SJomo 
24*03746da3SJomo impl GlobalFile {
new() -> Self25*03746da3SJomo     pub fn new() -> Self {
26*03746da3SJomo         let passwd = open_file("/etc/passwd");
27*03746da3SJomo         let shadow = open_file("/etc/shadow");
28*03746da3SJomo         let group = open_file("/etc/group");
29*03746da3SJomo         let gshadow = open_file("/etc/gshadow");
30*03746da3SJomo         Self {
31*03746da3SJomo             passwd_file: passwd,
32*03746da3SJomo             shadow_file: shadow,
33*03746da3SJomo             group_file: group,
34*03746da3SJomo             gshadow_file: gshadow,
35*03746da3SJomo         }
36*03746da3SJomo     }
37*03746da3SJomo }
38*03746da3SJomo 
open_file(file_path: &str) -> File39*03746da3SJomo fn open_file(file_path: &str) -> File {
40*03746da3SJomo     let r = OpenOptions::new()
41*03746da3SJomo         .read(true)
42*03746da3SJomo         .write(true)
43*03746da3SJomo         .append(true)
44*03746da3SJomo         .open(file_path);
45*03746da3SJomo 
46*03746da3SJomo     let exit_status = match file_path {
47*03746da3SJomo         "/etc/group" => ExitStatus::GroupFile,
48*03746da3SJomo         "/etc/gshadow" => ExitStatus::GshadowFile,
49*03746da3SJomo         "/etc/passwd" => ExitStatus::PasswdFile,
50*03746da3SJomo         "/etc/shadow" => ExitStatus::ShadowFile,
51*03746da3SJomo         _ => ExitStatus::InvalidArg,
52*03746da3SJomo     };
53*03746da3SJomo 
54*03746da3SJomo     if r.is_err() {
55*03746da3SJomo         ErrorHandler::error_handle(format!("Can't open file: {}", file_path), exit_status);
56*03746da3SJomo     }
57*03746da3SJomo 
58*03746da3SJomo     r.unwrap()
59*03746da3SJomo }
60*03746da3SJomo 
61*03746da3SJomo /// useradd执行器
62*03746da3SJomo pub struct UAddExecutor;
63*03746da3SJomo 
64*03746da3SJomo impl UAddExecutor {
65*03746da3SJomo     /// **执行useradd**
66*03746da3SJomo     ///
67*03746da3SJomo     /// ## 参数
68*03746da3SJomo     /// - `info`: 用户信息
execute(info: UAddInfo)69*03746da3SJomo     pub fn execute(info: UAddInfo) {
70*03746da3SJomo         // 创建用户home目录
71*03746da3SJomo         let home = info.home_dir.clone();
72*03746da3SJomo         let dir_builder = fs::DirBuilder::new();
73*03746da3SJomo         if dir_builder.create(home.clone()).is_err() {
74*03746da3SJomo             ErrorHandler::error_handle(
75*03746da3SJomo                 format!("unable to create {}", home),
76*03746da3SJomo                 ExitStatus::CreateHomeFail,
77*03746da3SJomo             );
78*03746da3SJomo         }
79*03746da3SJomo 
80*03746da3SJomo         Self::write_passwd_file(&info);
81*03746da3SJomo         Self::write_shadow_file(&info);
82*03746da3SJomo         Self::write_group_file(&info);
83*03746da3SJomo         Self::write_gshadow_file(&info);
84*03746da3SJomo     }
85*03746da3SJomo 
86*03746da3SJomo     /// 写入/etc/passwd文件:添加用户信息
write_passwd_file(info: &UAddInfo)87*03746da3SJomo     fn write_passwd_file(info: &UAddInfo) {
88*03746da3SJomo         let userinfo: String = info.clone().into();
89*03746da3SJomo         GLOBAL_FILE
90*03746da3SJomo             .lock()
91*03746da3SJomo             .unwrap()
92*03746da3SJomo             .passwd_file
93*03746da3SJomo             .write_all(userinfo.as_bytes())
94*03746da3SJomo             .unwrap();
95*03746da3SJomo     }
96*03746da3SJomo 
97*03746da3SJomo     /// 写入/etc/group文件:将用户添加到对应用户组中
write_group_file(info: &UAddInfo)98*03746da3SJomo     fn write_group_file(info: &UAddInfo) {
99*03746da3SJomo         if info.group == info.username {
100*03746da3SJomo             return;
101*03746da3SJomo         }
102*03746da3SJomo 
103*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
104*03746da3SJomo         let content = read_to_string(&guard.group_file);
105*03746da3SJomo         let mut new_content = String::new();
106*03746da3SJomo         for line in content.lines() {
107*03746da3SJomo             let mut field = line.split(":").collect::<Vec<&str>>();
108*03746da3SJomo             let mut users = field.last().unwrap().split(",").collect::<Vec<&str>>();
109*03746da3SJomo             users = users
110*03746da3SJomo                 .into_iter()
111*03746da3SJomo                 .filter(|username| !username.is_empty())
112*03746da3SJomo                 .collect::<Vec<&str>>();
113*03746da3SJomo             if field[0].eq(info.group.as_str()) && !users.contains(&info.username.as_str()) {
114*03746da3SJomo                 users.push(info.username.as_str());
115*03746da3SJomo             }
116*03746da3SJomo 
117*03746da3SJomo             let new_users = users.join(",");
118*03746da3SJomo             field[3] = new_users.as_str();
119*03746da3SJomo             new_content.push_str(format!("{}\n", field.join(":")).as_str());
120*03746da3SJomo         }
121*03746da3SJomo 
122*03746da3SJomo         guard.group_file.set_len(0).unwrap();
123*03746da3SJomo         guard.group_file.seek(std::io::SeekFrom::Start(0)).unwrap();
124*03746da3SJomo         guard.group_file.write_all(new_content.as_bytes()).unwrap();
125*03746da3SJomo         guard.group_file.flush().unwrap();
126*03746da3SJomo     }
127*03746da3SJomo 
128*03746da3SJomo     /// 写入/etc/shadow文件:添加用户口令相关信息
write_shadow_file(info: &UAddInfo)129*03746da3SJomo     fn write_shadow_file(info: &UAddInfo) {
130*03746da3SJomo         let data = format!("{}::::::::\n", info.username,);
131*03746da3SJomo         GLOBAL_FILE
132*03746da3SJomo             .lock()
133*03746da3SJomo             .unwrap()
134*03746da3SJomo             .shadow_file
135*03746da3SJomo             .write_all(data.as_bytes())
136*03746da3SJomo             .unwrap();
137*03746da3SJomo     }
138*03746da3SJomo 
139*03746da3SJomo     /// 写入/etc/gshadow文件:将用户添加到对应用户组中
write_gshadow_file(info: &UAddInfo)140*03746da3SJomo     fn write_gshadow_file(info: &UAddInfo) {
141*03746da3SJomo         if info.group == info.username {
142*03746da3SJomo             return;
143*03746da3SJomo         }
144*03746da3SJomo 
145*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
146*03746da3SJomo         let content = read_to_string(&guard.gshadow_file);
147*03746da3SJomo         let mut new_content = String::new();
148*03746da3SJomo         for line in content.lines() {
149*03746da3SJomo             let mut field = line.split(":").collect::<Vec<&str>>();
150*03746da3SJomo             let mut users = field.last().unwrap().split(",").collect::<Vec<&str>>();
151*03746da3SJomo             users = users
152*03746da3SJomo                 .into_iter()
153*03746da3SJomo                 .filter(|username| !username.is_empty())
154*03746da3SJomo                 .collect::<Vec<&str>>();
155*03746da3SJomo             if field[0].eq(info.group.as_str()) && !users.contains(&info.username.as_str()) {
156*03746da3SJomo                 users.push(info.username.as_str());
157*03746da3SJomo             }
158*03746da3SJomo 
159*03746da3SJomo             let new_users = users.join(",");
160*03746da3SJomo             field[3] = new_users.as_str();
161*03746da3SJomo             new_content.push_str(format!("{}\n", field.join(":")).as_str());
162*03746da3SJomo         }
163*03746da3SJomo         guard.gshadow_file.set_len(0).unwrap();
164*03746da3SJomo         guard
165*03746da3SJomo             .gshadow_file
166*03746da3SJomo             .seek(std::io::SeekFrom::Start(0))
167*03746da3SJomo             .unwrap();
168*03746da3SJomo         guard
169*03746da3SJomo             .gshadow_file
170*03746da3SJomo             .write_all(new_content.as_bytes())
171*03746da3SJomo             .unwrap();
172*03746da3SJomo         guard.gshadow_file.flush().unwrap();
173*03746da3SJomo     }
174*03746da3SJomo }
175*03746da3SJomo 
176*03746da3SJomo /// userdel执行器
177*03746da3SJomo pub struct UDelExecutor;
178*03746da3SJomo 
179*03746da3SJomo impl UDelExecutor {
180*03746da3SJomo     /// **执行userdel**
181*03746da3SJomo     ///
182*03746da3SJomo     /// ## 参数
183*03746da3SJomo     /// - `info`: 用户信息
execute(info: UDelInfo)184*03746da3SJomo     pub fn execute(info: UDelInfo) {
185*03746da3SJomo         // 移除home目录
186*03746da3SJomo         if let Some(home) = info.home.clone() {
187*03746da3SJomo             std::fs::remove_dir_all(home).unwrap();
188*03746da3SJomo         }
189*03746da3SJomo 
190*03746da3SJomo         Self::update_passwd_file(&info);
191*03746da3SJomo         Self::update_shadow_file(&info);
192*03746da3SJomo         Self::update_group_file(&info);
193*03746da3SJomo         Self::update_gshadow_file(&info);
194*03746da3SJomo     }
195*03746da3SJomo 
196*03746da3SJomo     /// 更新/etc/passwd文件: 删除用户信息
update_passwd_file(info: &UDelInfo)197*03746da3SJomo     fn update_passwd_file(info: &UDelInfo) {
198*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
199*03746da3SJomo         let content = read_to_string(&guard.passwd_file);
200*03746da3SJomo         let lines: Vec<&str> = content.lines().collect();
201*03746da3SJomo         let new_content = lines
202*03746da3SJomo             .into_iter()
203*03746da3SJomo             .filter(|&line| {
204*03746da3SJomo                 let field = line.split(':').collect::<Vec<&str>>();
205*03746da3SJomo                 field[0] != info.username.as_str()
206*03746da3SJomo             })
207*03746da3SJomo             .collect::<Vec<&str>>()
208*03746da3SJomo             .join("\n");
209*03746da3SJomo 
210*03746da3SJomo         guard.passwd_file.set_len(0).unwrap();
211*03746da3SJomo         guard.passwd_file.seek(std::io::SeekFrom::Start(0)).unwrap();
212*03746da3SJomo         guard.passwd_file.write_all(new_content.as_bytes()).unwrap();
213*03746da3SJomo         guard.passwd_file.flush().unwrap();
214*03746da3SJomo     }
215*03746da3SJomo 
216*03746da3SJomo     /// 更新/etc/group文件: 将用户从组中移除
update_group_file(info: &UDelInfo)217*03746da3SJomo     fn update_group_file(info: &UDelInfo) {
218*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
219*03746da3SJomo         let content = read_to_string(&guard.group_file);
220*03746da3SJomo         let mut new_content = String::new();
221*03746da3SJomo         for line in content.lines() {
222*03746da3SJomo             let mut field = line.split(':').collect::<Vec<&str>>();
223*03746da3SJomo             let mut users = field.last().unwrap().split(",").collect::<Vec<&str>>();
224*03746da3SJomo             if users.contains(&info.username.as_str()) {
225*03746da3SJomo                 field.remove(field.len() - 1);
226*03746da3SJomo                 users.remove(
227*03746da3SJomo                     users
228*03746da3SJomo                         .iter()
229*03746da3SJomo                         .position(|&x| x == info.username.as_str())
230*03746da3SJomo                         .unwrap(),
231*03746da3SJomo                 );
232*03746da3SJomo                 let users = users.join(",");
233*03746da3SJomo                 field.push(&users.as_str());
234*03746da3SJomo                 new_content.push_str(format!("{}\n", field.join(":").as_str()).as_str());
235*03746da3SJomo             } else {
236*03746da3SJomo                 new_content.push_str(format!("{}\n", field.join(":").as_str()).as_str());
237*03746da3SJomo             }
238*03746da3SJomo 
239*03746da3SJomo             guard.group_file.set_len(0).unwrap();
240*03746da3SJomo             guard.group_file.seek(std::io::SeekFrom::Start(0)).unwrap();
241*03746da3SJomo             guard.group_file.write_all(new_content.as_bytes()).unwrap();
242*03746da3SJomo             guard.group_file.flush().unwrap();
243*03746da3SJomo         }
244*03746da3SJomo     }
245*03746da3SJomo 
246*03746da3SJomo     /// 更新/etc/shadow文件: 将用户信息删去
update_shadow_file(info: &UDelInfo)247*03746da3SJomo     fn update_shadow_file(info: &UDelInfo) {
248*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
249*03746da3SJomo         let content = read_to_string(&guard.shadow_file);
250*03746da3SJomo         let lines: Vec<&str> = content.lines().collect();
251*03746da3SJomo         let new_content = lines
252*03746da3SJomo             .into_iter()
253*03746da3SJomo             .filter(|&line| !line.contains(&info.username))
254*03746da3SJomo             .collect::<Vec<&str>>()
255*03746da3SJomo             .join("\n");
256*03746da3SJomo 
257*03746da3SJomo         guard.shadow_file.set_len(0).unwrap();
258*03746da3SJomo         guard.shadow_file.seek(std::io::SeekFrom::Start(0)).unwrap();
259*03746da3SJomo         guard.shadow_file.write_all(new_content.as_bytes()).unwrap();
260*03746da3SJomo         guard.shadow_file.flush().unwrap();
261*03746da3SJomo     }
262*03746da3SJomo 
263*03746da3SJomo     /// 更新/etc/gshadow文件: 将用户从组中移除
update_gshadow_file(info: &UDelInfo)264*03746da3SJomo     fn update_gshadow_file(info: &UDelInfo) {
265*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
266*03746da3SJomo         let content = read_to_string(&guard.gshadow_file);
267*03746da3SJomo         let mut new_content = String::new();
268*03746da3SJomo         for line in content.lines() {
269*03746da3SJomo             let mut field = line.split(':').collect::<Vec<&str>>();
270*03746da3SJomo             let mut users = field.last().unwrap().split(",").collect::<Vec<&str>>();
271*03746da3SJomo             if users.contains(&info.username.as_str()) {
272*03746da3SJomo                 field.remove(field.len() - 1);
273*03746da3SJomo                 users.remove(
274*03746da3SJomo                     users
275*03746da3SJomo                         .iter()
276*03746da3SJomo                         .position(|&x| x == info.username.as_str())
277*03746da3SJomo                         .unwrap(),
278*03746da3SJomo                 );
279*03746da3SJomo                 let users = users.join(",");
280*03746da3SJomo                 field.push(&users.as_str());
281*03746da3SJomo                 new_content.push_str(format!("{}\n", field.join(":").as_str()).as_str());
282*03746da3SJomo             } else {
283*03746da3SJomo                 new_content.push_str(format!("{}\n", field.join(":").as_str()).as_str());
284*03746da3SJomo             }
285*03746da3SJomo 
286*03746da3SJomo             guard.gshadow_file.set_len(0).unwrap();
287*03746da3SJomo             guard
288*03746da3SJomo                 .gshadow_file
289*03746da3SJomo                 .seek(std::io::SeekFrom::Start(0))
290*03746da3SJomo                 .unwrap();
291*03746da3SJomo             guard
292*03746da3SJomo                 .gshadow_file
293*03746da3SJomo                 .write_all(new_content.as_bytes())
294*03746da3SJomo                 .unwrap();
295*03746da3SJomo             guard.gshadow_file.flush().unwrap();
296*03746da3SJomo         }
297*03746da3SJomo     }
298*03746da3SJomo }
299*03746da3SJomo 
300*03746da3SJomo /// usermod执行器
301*03746da3SJomo pub struct UModExecutor;
302*03746da3SJomo 
303*03746da3SJomo impl UModExecutor {
304*03746da3SJomo     /// **执行usermod**
305*03746da3SJomo     ///
306*03746da3SJomo     /// ## 参数
307*03746da3SJomo     /// - `info`: 用户信息
execute(mut info: UModInfo)308*03746da3SJomo     pub fn execute(mut info: UModInfo) {
309*03746da3SJomo         // 创建new_home
310*03746da3SJomo         if let Some(new_home) = &info.new_home {
311*03746da3SJomo             let dir_builder = fs::DirBuilder::new();
312*03746da3SJomo             if dir_builder.create(new_home.clone()).is_err() {
313*03746da3SJomo                 ErrorHandler::error_handle(
314*03746da3SJomo                     format!("unable to create {}", new_home),
315*03746da3SJomo                     ExitStatus::CreateHomeFail,
316*03746da3SJomo                 );
317*03746da3SJomo             }
318*03746da3SJomo         }
319*03746da3SJomo 
320*03746da3SJomo         Self::update_passwd_file(&info);
321*03746da3SJomo         Self::update_shadow_file(&info);
322*03746da3SJomo         Self::update_group_file(&mut info);
323*03746da3SJomo         Self::update_gshadow_file(&info);
324*03746da3SJomo     }
325*03746da3SJomo 
326*03746da3SJomo     /// 更新/etc/passwd文件的username、uid、comment、home、shell
update_passwd_file(info: &UModInfo)327*03746da3SJomo     fn update_passwd_file(info: &UModInfo) {
328*03746da3SJomo         let mut new_content = String::new();
329*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
330*03746da3SJomo         let content = read_to_string(&guard.passwd_file);
331*03746da3SJomo         for line in content.lines() {
332*03746da3SJomo             let mut fields = line.split(':').collect::<Vec<&str>>();
333*03746da3SJomo             if fields[0] == info.username {
334*03746da3SJomo                 if let Some(new_username) = &info.new_name {
335*03746da3SJomo                     fields[0] = new_username;
336*03746da3SJomo                 }
337*03746da3SJomo                 if let Some(new_uid) = &info.new_uid {
338*03746da3SJomo                     fields[2] = new_uid;
339*03746da3SJomo                 }
340*03746da3SJomo                 if let Some(new_gid) = &info.new_gid {
341*03746da3SJomo                     fields[3] = new_gid;
342*03746da3SJomo                 }
343*03746da3SJomo                 if let Some(new_comment) = &info.new_comment {
344*03746da3SJomo                     fields[4] = new_comment;
345*03746da3SJomo                 }
346*03746da3SJomo                 if let Some(new_home) = &info.new_home {
347*03746da3SJomo                     fields[5] = new_home;
348*03746da3SJomo                 }
349*03746da3SJomo                 if let Some(new_shell) = &info.new_shell {
350*03746da3SJomo                     fields[6] = new_shell;
351*03746da3SJomo                 }
352*03746da3SJomo                 new_content.push_str(format!("{}\n", fields.join(":")).as_str());
353*03746da3SJomo             } else {
354*03746da3SJomo                 new_content.push_str(format!("{}\n", line).as_str());
355*03746da3SJomo             }
356*03746da3SJomo 
357*03746da3SJomo             guard.passwd_file.set_len(0).unwrap();
358*03746da3SJomo             guard.passwd_file.seek(std::io::SeekFrom::Start(0)).unwrap();
359*03746da3SJomo             guard.passwd_file.write_all(new_content.as_bytes()).unwrap();
360*03746da3SJomo             guard.passwd_file.flush().unwrap();
361*03746da3SJomo         }
362*03746da3SJomo     }
363*03746da3SJomo 
364*03746da3SJomo     /// 更新/etc/group文件中各用户组中的用户
update_group_file(info: &mut UModInfo)365*03746da3SJomo     fn update_group_file(info: &mut UModInfo) {
366*03746da3SJomo         let mut name = info.username.clone();
367*03746da3SJomo         if let Some(new_name) = &info.new_name {
368*03746da3SJomo             name = new_name.clone();
369*03746da3SJomo         }
370*03746da3SJomo         let mut new_content = String::new();
371*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
372*03746da3SJomo         let content = read_to_string(&guard.group_file);
373*03746da3SJomo         for line in content.lines() {
374*03746da3SJomo             let mut fields = line.split(':').collect::<Vec<&str>>();
375*03746da3SJomo             let mut users = fields[3].split(",").collect::<Vec<&str>>();
376*03746da3SJomo             users = users
377*03746da3SJomo                 .into_iter()
378*03746da3SJomo                 .filter(|username| !username.is_empty())
379*03746da3SJomo                 .collect::<Vec<&str>>();
380*03746da3SJomo             if let Some(idx) = users.iter().position(|&r| r == info.username) {
381*03746da3SJomo                 if let Some(gid) = &info.new_gid {
382*03746da3SJomo                     // 换组,将用户从当前组删去
383*03746da3SJomo                     if gid != fields[2] {
384*03746da3SJomo                         users.remove(idx);
385*03746da3SJomo                     } else {
386*03746da3SJomo                         info.new_group = Some(fields[0].to_string())
387*03746da3SJomo                     }
388*03746da3SJomo                 } else {
389*03746da3SJomo                     // 不换组但是要更新名字
390*03746da3SJomo                     users[idx] = &name;
391*03746da3SJomo                 }
392*03746da3SJomo             }
393*03746da3SJomo 
394*03746da3SJomo             if let Some(groups) = &info.groups {
395*03746da3SJomo                 if groups.contains(&fields[0].to_string()) && !users.contains(&name.as_str()) {
396*03746da3SJomo                     users.push(&name);
397*03746da3SJomo                 }
398*03746da3SJomo             }
399*03746da3SJomo 
400*03746da3SJomo             let new_users = users.join(",");
401*03746da3SJomo             fields[3] = new_users.as_str();
402*03746da3SJomo             new_content.push_str(format!("{}\n", fields.join(":")).as_str());
403*03746da3SJomo         }
404*03746da3SJomo 
405*03746da3SJomo         guard.group_file.set_len(0).unwrap();
406*03746da3SJomo         guard.group_file.seek(std::io::SeekFrom::Start(0)).unwrap();
407*03746da3SJomo         guard.group_file.write_all(new_content.as_bytes()).unwrap();
408*03746da3SJomo         guard.group_file.flush().unwrap();
409*03746da3SJomo     }
410*03746da3SJomo 
411*03746da3SJomo     /// 更新/etc/shadow文件的username
update_shadow_file(info: &UModInfo)412*03746da3SJomo     fn update_shadow_file(info: &UModInfo) {
413*03746da3SJomo         if let Some(new_name) = &info.new_name {
414*03746da3SJomo             let mut new_content = String::new();
415*03746da3SJomo             let mut guard = GLOBAL_FILE.lock().unwrap();
416*03746da3SJomo             let content = read_to_string(&guard.shadow_file);
417*03746da3SJomo             for line in content.lines() {
418*03746da3SJomo                 let mut fields = line.split(':').collect::<Vec<&str>>();
419*03746da3SJomo                 if fields[0] == info.username {
420*03746da3SJomo                     fields[0] = new_name;
421*03746da3SJomo                     new_content.push_str(format!("{}\n", fields.join(":")).as_str());
422*03746da3SJomo                 } else {
423*03746da3SJomo                     new_content.push_str(format!("{}\n", line).as_str());
424*03746da3SJomo                 }
425*03746da3SJomo             }
426*03746da3SJomo 
427*03746da3SJomo             guard.shadow_file.set_len(0).unwrap();
428*03746da3SJomo             guard.shadow_file.seek(std::io::SeekFrom::Start(0)).unwrap();
429*03746da3SJomo             guard.shadow_file.write_all(new_content.as_bytes()).unwrap();
430*03746da3SJomo             guard.shadow_file.flush().unwrap();
431*03746da3SJomo         }
432*03746da3SJomo     }
433*03746da3SJomo 
434*03746da3SJomo     /// 更新/etc/gshadow文件中各用户组中的用户
update_gshadow_file(info: &UModInfo)435*03746da3SJomo     fn update_gshadow_file(info: &UModInfo) {
436*03746da3SJomo         let mut name = info.username.clone();
437*03746da3SJomo         if let Some(new_name) = &info.new_name {
438*03746da3SJomo             name = new_name.clone();
439*03746da3SJomo         }
440*03746da3SJomo         let mut new_content = String::new();
441*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
442*03746da3SJomo         let content = read_to_string(&guard.gshadow_file);
443*03746da3SJomo         for line in content.lines() {
444*03746da3SJomo             let mut fields = line.split(':').collect::<Vec<&str>>();
445*03746da3SJomo             let mut users = fields[3].split(",").collect::<Vec<&str>>();
446*03746da3SJomo             users = users
447*03746da3SJomo                 .into_iter()
448*03746da3SJomo                 .filter(|username| !username.is_empty())
449*03746da3SJomo                 .collect::<Vec<&str>>();
450*03746da3SJomo             if let Some(idx) = users.iter().position(|&r| r == info.username) {
451*03746da3SJomo                 if let Some(group) = &info.new_group {
452*03746da3SJomo                     // 换组,将用户从当前组删去
453*03746da3SJomo                     if group != fields[0] {
454*03746da3SJomo                         users.remove(idx);
455*03746da3SJomo                     }
456*03746da3SJomo                 } else {
457*03746da3SJomo                     // 不换组但是要更新名字
458*03746da3SJomo                     users[idx] = &name;
459*03746da3SJomo                 }
460*03746da3SJomo             }
461*03746da3SJomo 
462*03746da3SJomo             let tmp = format!(",{}", name);
463*03746da3SJomo             if let Some(groups) = &info.groups {
464*03746da3SJomo                 if groups.contains(&fields[0].to_string()) && !users.contains(&name.as_str()) {
465*03746da3SJomo                     if users.is_empty() {
466*03746da3SJomo                         users.push(&name);
467*03746da3SJomo                     } else {
468*03746da3SJomo                         users.push(tmp.as_str());
469*03746da3SJomo                     }
470*03746da3SJomo                 }
471*03746da3SJomo             }
472*03746da3SJomo 
473*03746da3SJomo             let new_users = users.join(",");
474*03746da3SJomo             fields[3] = new_users.as_str();
475*03746da3SJomo             new_content.push_str(format!("{}\n", fields.join(":")).as_str());
476*03746da3SJomo         }
477*03746da3SJomo 
478*03746da3SJomo         guard.gshadow_file.set_len(0).unwrap();
479*03746da3SJomo         guard
480*03746da3SJomo             .gshadow_file
481*03746da3SJomo             .seek(std::io::SeekFrom::Start(0))
482*03746da3SJomo             .unwrap();
483*03746da3SJomo         guard
484*03746da3SJomo             .gshadow_file
485*03746da3SJomo             .write_all(new_content.as_bytes())
486*03746da3SJomo             .unwrap();
487*03746da3SJomo         guard.gshadow_file.flush().unwrap();
488*03746da3SJomo     }
489*03746da3SJomo }
490*03746da3SJomo 
491*03746da3SJomo /// passwd执行器
492*03746da3SJomo pub struct PasswdExecutor;
493*03746da3SJomo 
494*03746da3SJomo impl PasswdExecutor {
495*03746da3SJomo     /// **执行passwd**
496*03746da3SJomo     ///
497*03746da3SJomo     /// ## 参数
498*03746da3SJomo     /// - `info`: 用户密码信息
execute(info: PasswdInfo)499*03746da3SJomo     pub fn execute(info: PasswdInfo) {
500*03746da3SJomo         Self::update_passwd_file(&info);
501*03746da3SJomo         Self::update_shadow_file(&info);
502*03746da3SJomo     }
503*03746da3SJomo 
504*03746da3SJomo     /// 更新/etc/passwd文件: 修改用户密码
update_passwd_file(info: &PasswdInfo)505*03746da3SJomo     fn update_passwd_file(info: &PasswdInfo) {
506*03746da3SJomo         let mut new_content = String::new();
507*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
508*03746da3SJomo         let content = read_to_string(&guard.passwd_file);
509*03746da3SJomo         for line in content.lines() {
510*03746da3SJomo             let mut field = line.split(':').collect::<Vec<_>>();
511*03746da3SJomo             if field[0] == info.username {
512*03746da3SJomo                 if info.new_password.is_empty() {
513*03746da3SJomo                     field[1] = "";
514*03746da3SJomo                 } else {
515*03746da3SJomo                     field[1] = "x";
516*03746da3SJomo                 }
517*03746da3SJomo             }
518*03746da3SJomo             new_content.push_str(format!("{}\n", field.join(":")).as_str());
519*03746da3SJomo         }
520*03746da3SJomo 
521*03746da3SJomo         guard.passwd_file.set_len(0).unwrap();
522*03746da3SJomo         guard.passwd_file.seek(std::io::SeekFrom::Start(0)).unwrap();
523*03746da3SJomo         guard.passwd_file.write_all(new_content.as_bytes()).unwrap();
524*03746da3SJomo         guard.passwd_file.flush().unwrap();
525*03746da3SJomo     }
526*03746da3SJomo 
527*03746da3SJomo     /// 更新/etc/shadow文件: 修改用户密码
update_shadow_file(info: &PasswdInfo)528*03746da3SJomo     fn update_shadow_file(info: &PasswdInfo) {
529*03746da3SJomo         let mut new_content = String::new();
530*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
531*03746da3SJomo         let content = read_to_string(&guard.shadow_file);
532*03746da3SJomo         for line in content.lines() {
533*03746da3SJomo             let mut field = line.split(':').collect::<Vec<_>>();
534*03746da3SJomo             if field[0] == info.username {
535*03746da3SJomo                 field[1] = info.new_password.as_str();
536*03746da3SJomo             }
537*03746da3SJomo             new_content.push_str(format!("{}\n", field.join(":")).as_str());
538*03746da3SJomo         }
539*03746da3SJomo 
540*03746da3SJomo         guard.shadow_file.set_len(0).unwrap();
541*03746da3SJomo         guard.shadow_file.seek(std::io::SeekFrom::Start(0)).unwrap();
542*03746da3SJomo         guard.shadow_file.write_all(new_content.as_bytes()).unwrap();
543*03746da3SJomo         guard.shadow_file.flush().unwrap();
544*03746da3SJomo     }
545*03746da3SJomo }
546*03746da3SJomo 
547*03746da3SJomo /// groupadd执行器
548*03746da3SJomo pub struct GAddExecutor;
549*03746da3SJomo 
550*03746da3SJomo impl GAddExecutor {
551*03746da3SJomo     /// **执行groupadd**
552*03746da3SJomo     ///
553*03746da3SJomo     /// ## 参数
554*03746da3SJomo     /// - `info`: 组信息
execute(info: GAddInfo)555*03746da3SJomo     pub fn execute(info: GAddInfo) {
556*03746da3SJomo         Self::write_group_file(&info);
557*03746da3SJomo         Self::write_gshadow_file(&info);
558*03746da3SJomo     }
559*03746da3SJomo 
560*03746da3SJomo     /// 写入/etc/group文件: 添加用户组信息
write_group_file(info: &GAddInfo)561*03746da3SJomo     fn write_group_file(info: &GAddInfo) {
562*03746da3SJomo         GLOBAL_FILE
563*03746da3SJomo             .lock()
564*03746da3SJomo             .unwrap()
565*03746da3SJomo             .group_file
566*03746da3SJomo             .write_all(info.to_string_group().as_bytes())
567*03746da3SJomo             .unwrap()
568*03746da3SJomo     }
569*03746da3SJomo 
570*03746da3SJomo     /// 写入/etc/gshadow文件: 添加用户组密码信息
write_gshadow_file(info: &GAddInfo)571*03746da3SJomo     fn write_gshadow_file(info: &GAddInfo) {
572*03746da3SJomo         GLOBAL_FILE
573*03746da3SJomo             .lock()
574*03746da3SJomo             .unwrap()
575*03746da3SJomo             .gshadow_file
576*03746da3SJomo             .write_all(info.to_string_gshadow().as_bytes())
577*03746da3SJomo             .unwrap();
578*03746da3SJomo     }
579*03746da3SJomo }
580*03746da3SJomo 
581*03746da3SJomo /// groupdel执行器
582*03746da3SJomo pub struct GDelExecutor;
583*03746da3SJomo 
584*03746da3SJomo impl GDelExecutor {
585*03746da3SJomo     /// **执行groupdel**
586*03746da3SJomo     ///
587*03746da3SJomo     /// ## 参数
588*03746da3SJomo     /// - `info`: 组信息
execute(info: GDelInfo)589*03746da3SJomo     pub fn execute(info: GDelInfo) {
590*03746da3SJomo         Self::update_group_file(&info);
591*03746da3SJomo         Self::update_gshadow_file(&info);
592*03746da3SJomo     }
593*03746da3SJomo 
594*03746da3SJomo     /// 更新/etc/group文件:删除用户组
update_group_file(info: &GDelInfo)595*03746da3SJomo     pub fn update_group_file(info: &GDelInfo) {
596*03746da3SJomo         let mut new_content = String::new();
597*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
598*03746da3SJomo         let content = read_to_string(&guard.group_file);
599*03746da3SJomo         for line in content.lines() {
600*03746da3SJomo             let field = line.split(':').collect::<Vec<&str>>();
601*03746da3SJomo             if field[0] != info.groupname {
602*03746da3SJomo                 new_content.push_str(format!("{}\n", line).as_str());
603*03746da3SJomo             }
604*03746da3SJomo         }
605*03746da3SJomo 
606*03746da3SJomo         guard.group_file.set_len(0).unwrap();
607*03746da3SJomo         guard.group_file.seek(std::io::SeekFrom::Start(0)).unwrap();
608*03746da3SJomo         guard.group_file.write_all(new_content.as_bytes()).unwrap();
609*03746da3SJomo         guard.group_file.flush().unwrap();
610*03746da3SJomo     }
611*03746da3SJomo 
612*03746da3SJomo     /// 更新/etc/gshadow文件:移除用户组
update_gshadow_file(info: &GDelInfo)613*03746da3SJomo     pub fn update_gshadow_file(info: &GDelInfo) {
614*03746da3SJomo         let mut new_content = String::new();
615*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
616*03746da3SJomo         let content = read_to_string(&guard.gshadow_file);
617*03746da3SJomo         for line in content.lines() {
618*03746da3SJomo             let field = line.split(':').collect::<Vec<&str>>();
619*03746da3SJomo             if field[0] != info.groupname {
620*03746da3SJomo                 new_content.push_str(format!("{}\n", line).as_str());
621*03746da3SJomo             }
622*03746da3SJomo         }
623*03746da3SJomo 
624*03746da3SJomo         guard.gshadow_file.set_len(0).unwrap();
625*03746da3SJomo         guard
626*03746da3SJomo             .gshadow_file
627*03746da3SJomo             .seek(std::io::SeekFrom::Start(0))
628*03746da3SJomo             .unwrap();
629*03746da3SJomo         guard
630*03746da3SJomo             .gshadow_file
631*03746da3SJomo             .write_all(new_content.as_bytes())
632*03746da3SJomo             .unwrap();
633*03746da3SJomo         guard.gshadow_file.flush().unwrap();
634*03746da3SJomo     }
635*03746da3SJomo }
636*03746da3SJomo 
637*03746da3SJomo /// groupmod执行器
638*03746da3SJomo pub struct GModExecutor;
639*03746da3SJomo 
640*03746da3SJomo impl GModExecutor {
641*03746da3SJomo     /// **执行groupmod**
642*03746da3SJomo     ///
643*03746da3SJomo     /// ## 参数
644*03746da3SJomo     /// - `info`: 组信息
execute(info: GModInfo)645*03746da3SJomo     pub fn execute(info: GModInfo) {
646*03746da3SJomo         Self::update_passwd_file(&info);
647*03746da3SJomo         Self::update_group_file(&info);
648*03746da3SJomo         Self::update_gshadow_file(&info);
649*03746da3SJomo     }
650*03746da3SJomo 
651*03746da3SJomo     /// 更新/etc/group文件: 更新用户组信息
update_group_file(info: &GModInfo)652*03746da3SJomo     fn update_group_file(info: &GModInfo) {
653*03746da3SJomo         let mut new_content = String::new();
654*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
655*03746da3SJomo         let content = read_to_string(&guard.group_file);
656*03746da3SJomo         for line in content.lines() {
657*03746da3SJomo             let mut field = line.split(':').collect::<Vec<&str>>();
658*03746da3SJomo             if field[0] == info.groupname {
659*03746da3SJomo                 if let Some(new_groupname) = &info.new_groupname {
660*03746da3SJomo                     field[0] = new_groupname;
661*03746da3SJomo                 }
662*03746da3SJomo                 if let Some(new_gid) = &info.new_gid {
663*03746da3SJomo                     field[2] = new_gid;
664*03746da3SJomo                 }
665*03746da3SJomo             }
666*03746da3SJomo             new_content.push_str(format!("{}\n", field.join(":")).as_str());
667*03746da3SJomo         }
668*03746da3SJomo 
669*03746da3SJomo         guard.group_file.set_len(0).unwrap();
670*03746da3SJomo         guard.group_file.seek(std::io::SeekFrom::Start(0)).unwrap();
671*03746da3SJomo         guard.group_file.write_all(new_content.as_bytes()).unwrap();
672*03746da3SJomo         guard.group_file.flush().unwrap();
673*03746da3SJomo     }
674*03746da3SJomo 
675*03746da3SJomo     /// 更新/etc/gshadow文件: 更新用户组密码信息
update_gshadow_file(info: &GModInfo)676*03746da3SJomo     fn update_gshadow_file(info: &GModInfo) {
677*03746da3SJomo         let mut new_content = String::new();
678*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
679*03746da3SJomo         let content = read_to_string(&guard.gshadow_file);
680*03746da3SJomo         for line in content.lines() {
681*03746da3SJomo             let mut field = line.split(':').collect::<Vec<&str>>();
682*03746da3SJomo             if field[0] == info.groupname {
683*03746da3SJomo                 if let Some(new_groupname) = &info.new_groupname {
684*03746da3SJomo                     field[0] = new_groupname;
685*03746da3SJomo                 }
686*03746da3SJomo             }
687*03746da3SJomo             new_content.push_str(format!("{}\n", field.join(":")).as_str());
688*03746da3SJomo         }
689*03746da3SJomo 
690*03746da3SJomo         guard.gshadow_file.set_len(0).unwrap();
691*03746da3SJomo         guard
692*03746da3SJomo             .gshadow_file
693*03746da3SJomo             .seek(std::io::SeekFrom::Start(0))
694*03746da3SJomo             .unwrap();
695*03746da3SJomo         guard
696*03746da3SJomo             .gshadow_file
697*03746da3SJomo             .write_all(new_content.as_bytes())
698*03746da3SJomo             .unwrap();
699*03746da3SJomo         guard.gshadow_file.flush().unwrap();
700*03746da3SJomo     }
701*03746da3SJomo 
702*03746da3SJomo     /// 更新/etc/passwd文件: 更新用户组ID信息,因为用户组ID可能会被修改
update_passwd_file(info: &GModInfo)703*03746da3SJomo     fn update_passwd_file(info: &GModInfo) {
704*03746da3SJomo         let mut new_content = String::new();
705*03746da3SJomo         let mut guard = GLOBAL_FILE.lock().unwrap();
706*03746da3SJomo         let content = read_to_string(&guard.passwd_file);
707*03746da3SJomo         for line in content.lines() {
708*03746da3SJomo             let mut field = line.split(':').collect::<Vec<&str>>();
709*03746da3SJomo             if field[3] == info.gid {
710*03746da3SJomo                 if let Some(new_gid) = &info.new_gid {
711*03746da3SJomo                     field[3] = new_gid;
712*03746da3SJomo                 }
713*03746da3SJomo             }
714*03746da3SJomo             new_content.push_str(format!("{}\n", field.join(":")).as_str());
715*03746da3SJomo         }
716*03746da3SJomo 
717*03746da3SJomo         guard.passwd_file.set_len(0).unwrap();
718*03746da3SJomo         guard.passwd_file.seek(std::io::SeekFrom::Start(0)).unwrap();
719*03746da3SJomo         guard.passwd_file.write_all(new_content.as_bytes()).unwrap();
720*03746da3SJomo         guard.passwd_file.flush().unwrap();
721*03746da3SJomo     }
722*03746da3SJomo }
723*03746da3SJomo 
read_to_string(mut file: &File) -> String724*03746da3SJomo fn read_to_string(mut file: &File) -> String {
725*03746da3SJomo     file.seek(std::io::SeekFrom::Start(0)).unwrap();
726*03746da3SJomo     let mut content = String::new();
727*03746da3SJomo     file.read_to_string(&mut content).unwrap();
728*03746da3SJomo     content
729*03746da3SJomo }
730