1 //
2 // Copyright (c) 2010-2018 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Diagnostics;
10 
11 namespace Antmicro.Renode.Utilities
12 {
13     /// <summary>
14     /// Sudo tools. Set of methods related to the process elevation.
15     /// </summary>
16     public static class SudoTools
17     {
18         /// <summary>
19         /// Wraps the command into a sudo-tool call if necessary, creates a new Process object and exectues it.
20         /// </summary>
21         /// <description>
22         /// Checks whether user is root. If it is exectues command, id not tries to elevate priviledged and run the command.
23         /// </description>
24         /// <returns>The sudo execute.</returns>
25         /// <param name="command">Command.</param>
26         /// <param name = "arguments">Command's arguments.</param>
27         /// <param name="description">Optional description.</param>
EnsureSudoExecute(string command, string arguments = R, string description = R)28         public static Process EnsureSudoExecute(string command, string arguments = "", string description = "")
29         {
30             Process process;
31             process = Misc.IsRoot ? Process.Start(command, arguments) : SudoExecute(command + " " + arguments, description);
32             return process;
33         }
34 
35         /// <summary>
36         /// Tries to wrap existing Process, with supported sudo tool. It switched the command's filename and arguments, and wraps them
37         /// into a call to the supported sudo tool, if it's found.
38         /// </summary>
39         /// <param name="process">Process to be elevated.</param>
40         /// <param name="description">Process description.</param>
EnsureSudoProcess(Process process, string description = R)41         public static void EnsureSudoProcess(Process process, string description = "")
42         {
43             if(Misc.IsRoot)
44             {
45                 return;
46             }
47             Process sudoProcess = process;
48             string sudoName = FindSudoToolName();
49             if(string.IsNullOrWhiteSpace(sudoProcess.StartInfo.FileName))
50             {
51                 throw new ArgumentException("EnsureSudoProcess needs to work on a process with initliazed StartInfo.FileName.");
52             }
53             var command = sudoProcess.StartInfo.FileName + " " + sudoProcess.StartInfo.Arguments;
54             sudoProcess.StartInfo.Arguments = SudoDecorateCommand(sudoName, command, description);
55             sudoProcess.StartInfo.FileName = sudoName;
56         }
57 
58         /// <summary>
59         /// Finds the name of the sudo tool.
60         /// </summary>
61         /// <returns><c>true</c>, if sudo tool name was found, <c>false</c> otherwise.</returns>
62         /// <param name="name">Sudo tool name, if found.</param>
TryFindSudoToolName(out string name)63         private static bool TryFindSudoToolName(out string name)
64         {
65             name = default(string);
66             foreach(var nameToCheck in knownToolNames)
67             {
68                 if(Misc.IsCommandAvaialble(nameToCheck))
69                 {
70                     name = nameToCheck;
71                     return true;
72                 }
73             }
74             return false;
75         }
76 
77         /// <summary>
78         /// Finds the name of the sudo tool. Throwing version of <see cref="TryFindSudoToolName"/>.
79         /// </summary>
80         /// <returns>The sudo tool name.</returns>
FindSudoToolName()81         private static string FindSudoToolName()
82         {
83             string name;
84             if(!TryFindSudoToolName(out name))
85             {
86                 throw new PlatformNotSupportedException(
87                     String.Format("Error: No supported sudo tool found. Supported tools are {0}.", string.Join(", ", knownToolNames))
88                 );
89             }
90             return name;
91         }
92 
93         /// <summary>
94         /// Tries to find sudo tool, and execute the command with elevated rigths.
95         /// </summary>
96         /// <returns>The Process object, after the execution.</returns>
97         /// <param name="command">Command.</param>
98         /// <param name="description">Description.</param>
SudoExecute(string command, string description = R)99         private static Process SudoExecute(string command, string description = "")
100         {
101             string sudoName = FindSudoToolName();
102             Process process;
103             command = SudoDecorateCommand(sudoName, command, description);
104             process = Process.Start(sudoName, command);
105             return process;
106         }
107 
108         /// <summary>
109         /// Decorates the command for a specific sudo tool.
110         /// </summary>
111         /// <returns>The decorated command.</returns>
112         /// <param name="sudoName">Sudo tool name.</param>
113         /// <param name="command">Command to be decorated.</param>
114         /// <param name="description">Description.</param>
SudoDecorateCommand(string sudoName, string command, string description = R)115         private static string SudoDecorateCommand(string sudoName, string command, string description = "")
116         {
117             string result;
118 
119             switch(sudoName)
120             {
121                 // Tool specific adjustments.
122                 case "gksudo":
123                     result = string.Format(@"-D ""{0}"" ""{1}""", description, command);
124                     break;
125                 case "kdesudo":
126                     result = string.Format(@"-c ""{0}"" --comment ""{1}""", command, description);
127                     break;
128                 case "pkexec":
129                     // We do nothing, because 'pkexec' (version 0.105) doesn't accept description as a parameter.
130                 default:
131                     result = command;
132                     break;
133             }
134 
135             return result;
136         }
137 
138         /// <summary>
139         /// List of supported tool names.
140         /// </summary>
141         private static string[] knownToolNames = { "gksudo", "kdesudo", "pkexec" };
142     }
143 }
144 
145