1 /*
2   KeePass Password Safe - The Open-Source Password Manager
3   Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 
20 using System;
21 using System.Collections.Generic;
22 using System.Diagnostics;
23 using System.IO;
24 using System.Reflection;
25 using System.Text;
26 using System.Xml;
27 
28 namespace KeePassLib.Native
29 {
30 	internal sealed class SimpleStat
31 	{
32 		private readonly object m_oPermissions;
33 		private readonly long m_nUserId;
34 		private readonly long m_nGroupId;
35 
SimpleStat(object oPermissions, long nUserId, long nGroupId)36 		private SimpleStat(object oPermissions, long nUserId, long nGroupId)
37 		{
38 			if(oPermissions == null) throw new ArgumentNullException("oPermissions");
39 
40 			m_oPermissions = oPermissions;
41 			m_nUserId = nUserId;
42 			m_nGroupId = nGroupId;
43 		}
44 
Get(string strFilePath)45 		public static SimpleStat Get(string strFilePath)
46 		{
47 			try
48 			{
49 				Type tUfsi, tUfi;
50 				object oUfi = GetUnixFileInfo(strFilePath, out tUfsi, out tUfi);
51 				if(oUfi == null) return null;
52 
53 				PropertyInfo piPerm = tUfsi.GetProperty("FileAccessPermissions",
54 					BindingFlags.Public | BindingFlags.Instance);
55 				if(piPerm == null) { Debug.Assert(false); return null; }
56 				Debug.Assert(piPerm.PropertyType.IsEnum);
57 
58 				PropertyInfo piUser = tUfsi.GetProperty("OwnerUserId",
59 					BindingFlags.Public | BindingFlags.Instance);
60 				if(piUser == null) { Debug.Assert(false); return null; }
61 				Debug.Assert(piUser.PropertyType == typeof(long));
62 
63 				PropertyInfo piGroup = tUfsi.GetProperty("OwnerGroupId",
64 					BindingFlags.Public | BindingFlags.Instance);
65 				if(piGroup == null) { Debug.Assert(false); return null; }
66 				Debug.Assert(piGroup.PropertyType == typeof(long));
67 
68 				return new SimpleStat(piPerm.GetValue(oUfi, null),
69 					(long)piUser.GetValue(oUfi, null),
70 					(long)piGroup.GetValue(oUfi, null));
71 			}
72 			catch(Exception) { Debug.Assert(false); }
73 
74 			return null;
75 		}
76 
Set(string strFilePath, SimpleStat s)77 		public static void Set(string strFilePath, SimpleStat s)
78 		{
79 			if(s == null) { Debug.Assert(false); return; }
80 
81 			try
82 			{
83 				Type tUfsi, tUfi;
84 				object oUfi = GetUnixFileInfo(strFilePath, out tUfsi, out tUfi);
85 				if(oUfi == null) return;
86 
87 				PropertyInfo piPerm = tUfsi.GetProperty("FileAccessPermissions",
88 					BindingFlags.Public | BindingFlags.Instance);
89 				if(piPerm == null) { Debug.Assert(false); return; }
90 
91 				piPerm.SetValue(oUfi, s.m_oPermissions, null);
92 
93 				MethodInfo miOwner = tUfsi.GetMethod("SetOwner",
94 					new Type[] { typeof(long), typeof(long) });
95 				if(miOwner == null) { Debug.Assert(false); return; }
96 
97 				miOwner.Invoke(oUfi, new object[] { s.m_nUserId, s.m_nGroupId });
98 			}
99 			catch(Exception) { Debug.Assert(false); }
100 		}
101 
GetTypes(out Type tUfsi, out Type tUfi)102 		private static bool GetTypes(out Type tUfsi, out Type tUfi)
103 		{
104 			tUfsi = null;
105 			tUfi = null;
106 
107 			try
108 			{
109 				if(!NativeLib.IsUnix()) return false;
110 
111 				string strVer = typeof(XmlNode).Assembly.GetName().Version.ToString();
112 				string strPosix = "Mono.Posix, Version=" + strVer;
113 				Assembly asmPosix = Assembly.Load(strPosix);
114 				if(asmPosix == null) { Debug.Assert(false); return false; }
115 
116 				tUfsi = asmPosix.GetType("Mono.Unix.UnixFileSystemInfo", false);
117 				tUfi = asmPosix.GetType("Mono.Unix.UnixFileInfo", false);
118 
119 				bool b = ((tUfsi != null) && (tUfi != null));
120 				Debug.Assert(b);
121 				return b;
122 			}
123 			catch(Exception) { Debug.Assert(false); }
124 
125 			return false;
126 		}
127 
GetUnixFileInfo(string strFilePath, Type tUfi)128 		private static object GetUnixFileInfo(string strFilePath, Type tUfi)
129 		{
130 			if(string.IsNullOrEmpty(strFilePath)) { Debug.Assert(false); return null; }
131 
132 			try
133 			{
134 				if(!File.Exists(strFilePath)) { Debug.Assert(false); return null; }
135 
136 				return Activator.CreateInstance(tUfi, strFilePath);
137 			}
138 			catch(Exception) { Debug.Assert(false); }
139 
140 			return null;
141 		}
142 
GetUnixFileInfo(string strFilePath, out Type tUfsi, out Type tUfi)143 		private static object GetUnixFileInfo(string strFilePath,
144 			out Type tUfsi, out Type tUfi)
145 		{
146 			if(!GetTypes(out tUfsi, out tUfi)) return null;
147 			return GetUnixFileInfo(strFilePath, tUfi);
148 		}
149 	}
150 }
151