Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/main/src
diff options
context:
space:
mode:
authorJeffrey Stedfast <jeff@xamarin.com>2013-08-23 00:12:00 +0400
committerJeffrey Stedfast <jeff@xamarin.com>2013-08-23 00:30:12 +0400
commit5da4c31ddf0f3d8715fd790c98955e6633da667e (patch)
treeff80eb9526a66ddb5355f8f42b5c7f705815ad07 /main/src
parent7d54fecec88c410177391fad4f5167109fb3049f (diff)
[MacPlatform] A whole bunch of fixes to Keychain
1. Fixed support for unicode strings (by manual marshalling) 2. Fixed InternetPasswords to use the protocol & auth type 3. Fixed the path argument to not contain the query or leading / 4. Provide a nice label string for the key when veiwed in Keychain Access 5. Fixed to call CFRelease() on returned items for Find/AddInternetPassword
Diffstat (limited to 'main/src')
-rw-r--r--main/src/addins/MacPlatform/MacInterop/Keychain.cs296
1 files changed, 263 insertions, 33 deletions
diff --git a/main/src/addins/MacPlatform/MacInterop/Keychain.cs b/main/src/addins/MacPlatform/MacInterop/Keychain.cs
index b444165470..a371610e4c 100644
--- a/main/src/addins/MacPlatform/MacInterop/Keychain.cs
+++ b/main/src/addins/MacPlatform/MacInterop/Keychain.cs
@@ -26,17 +26,17 @@
using System;
using System.Linq;
-using System.Runtime.InteropServices;
+using System.Text;
using System.Collections.Generic;
-using MonoDevelop.Core;
-using MonoDevelop.Core.Serialization;
+using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
+using MonoDevelop.Core;
+
namespace MonoDevelop.MacInterop
{
public static class Keychain
{
-
#region P/Invoke signatures
const string SecurityLib = "/System/Library/Frameworks/Security.framework/Security";
@@ -55,24 +55,29 @@ namespace MonoDevelop.MacInterop
static extern OSStatus SecKeychainItemFreeContent (IntPtr attrList, IntPtr data);
[DllImport (SecurityLib)]
- static extern OSStatus SecKeychainAddGenericPassword (IntPtr keychain, uint serviceNameLength, string serviceName,
- uint accountNameLength, string accountName, uint passwordLength,
+ static extern OSStatus SecKeychainAddGenericPassword (IntPtr keychain, uint serviceNameLength, byte[] serviceName,
+ uint accountNameLength, byte[] accountName, uint passwordLength,
byte[] passwordData, ref IntPtr itemRef);
[DllImport (SecurityLib)]
- static extern OSStatus SecKeychainFindGenericPassword (IntPtr keychain, uint serviceNameLength, string serviceName,
- uint accountNameLength, string accountName, out uint passwordLength,
- out IntPtr passwordData, ref IntPtr itemRef);
+ static extern OSStatus SecKeychainFindGenericPassword (IntPtr keychain, uint serviceNameLength, byte[] serviceName,
+ uint accountNameLength, byte[] accountName, out uint passwordLength,
+ out IntPtr passwordData, ref IntPtr itemRef);
[DllImport (SecurityLib)]
- static extern OSStatus SecKeychainAddInternetPassword (IntPtr keychain, uint serverNameLength, string serverName, uint securityDomainLength,
- string securityDomain, uint accountNameLength, string accountName, uint pathLength,
- string path, ushort port, int protocol, int authenticationType,
- uint passwordLength, byte[] passwordData, ref IntPtr itemRef);
+ static extern OSStatus SecKeychainAddInternetPassword (IntPtr keychain, uint serverNameLength, byte[] serverName, uint securityDomainLength,
+ byte[] securityDomain, uint accountNameLength, byte[] accountName, uint pathLength,
+ byte[] path, ushort port, SecProtocolType protocol, SecAuthenticationType authType,
+ uint passwordLength, byte[] passwordData, ref IntPtr itemRef);
+ [DllImport (SecurityLib)]
+ static extern OSStatus SecKeychainFindInternetPassword (IntPtr keychain, uint serverNameLength, byte[] serverName, uint securityDomainLength,
+ byte[] securityDomain, uint accountNameLength, byte[] accountName, uint pathLength,
+ byte[] path, ushort port, SecProtocolType protocol, SecAuthenticationType authType,
+ out uint passwordLength, out IntPtr passwordData, ref IntPtr itemRef);
+
[DllImport (SecurityLib)]
- static extern OSStatus SecKeychainFindInternetPassword (IntPtr keychain, uint serverNameLength, string serverName, uint securityDomainLength,
- string securityDomain, uint accountNameLength, string accountName, uint pathLength,
- string path, ushort port, int protocol, int authenticationType,
- out uint passwordLength, out IntPtr passwordData, ref IntPtr itemRef);
+ static extern unsafe OSStatus SecKeychainItemCreateFromContent (SecItemClass itemClass, SecKeychainAttributeList *attrList,
+ uint passwordLength, byte[] password, IntPtr keychain,
+ IntPtr initialAccess, ref IntPtr itemRef);
[DllImport (SecurityLib)]
static extern OSStatus SecKeychainItemModifyAttributesAndData (IntPtr itemRef, IntPtr attrList, uint length, byte [] data);
@@ -111,6 +116,35 @@ namespace MonoDevelop.MacInterop
[DllImport (SecurityLib)]
static extern OSStatus SecCertificateGetData (IntPtr certificate, out CssmData data);
+
+
+ [StructLayout (LayoutKind.Sequential)]
+ struct SecKeychainAttributeList
+ {
+ public int Count;
+ public IntPtr Attrs;
+
+ public SecKeychainAttributeList (int count, IntPtr attrs)
+ {
+ Count = count;
+ Attrs = attrs;
+ }
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ struct SecKeychainAttribute
+ {
+ public SecItemAttr Tag;
+ public uint Length;
+ public IntPtr Data;
+
+ public SecKeychainAttribute (SecItemAttr tag, uint length, IntPtr data)
+ {
+ Tag = tag;
+ Length = length;
+ Data = data;
+ }
+ }
struct CssmData
{
@@ -254,7 +288,7 @@ namespace MonoDevelop.MacInterop
{
return GetAllSigningCertificates ().Where (x => {
var y = GetCertificateCommonName (x);
- return y != null && y.Length > 0 && nameCheck (y);
+ return !string.IsNullOrEmpty (y) && nameCheck (y);
});
}
@@ -343,25 +377,122 @@ namespace MonoDevelop.MacInterop
return cert.GetNameInfo (X509NameType.SimpleName, false);
}
- public static void AddInternetPassword (Uri uri, string password)
+ static SecAuthenticationType GetSecAuthenticationType (string query)
{
- IntPtr itemRef = IntPtr.Zero;
+ if (string.IsNullOrEmpty (query))
+ return SecAuthenticationType.Any;
+
+ string auth = "default";
+ foreach (var pair in query.Substring (1).Split (new char[] { '&' })) {
+ var kvp = pair.ToLowerInvariant ().Split (new char[] { '=' });
+ if (kvp[0] == "auth" && kvp.Length == 2) {
+ auth = kvp[1];
+ break;
+ }
+ }
+
+ switch (auth.ToLowerInvariant ()) {
+ case "ntlm": return SecAuthenticationType.NTLM;
+ case "msn": return SecAuthenticationType.MSN;
+ case "dpa": return SecAuthenticationType.DPA;
+ case "rpa": return SecAuthenticationType.RPA;
+ case "httpbasic": case "basic": return SecAuthenticationType.HTTPBasic;
+ case "httpdigest": case "digest": return SecAuthenticationType.HTTPDigest;
+ case "htmlform": case "form": return SecAuthenticationType.HTMLForm;
+ case "default": return SecAuthenticationType.Default;
+ default: return SecAuthenticationType.Any;
+ }
+ }
+
+ static SecProtocolType GetSecProtocolType (string protocol)
+ {
+ switch (protocol.ToLowerInvariant ()) {
+ case "ftp": return SecProtocolType.FTP;
+ case "ftpaccount": return SecProtocolType.FTPAccount;
+ case "http": return SecProtocolType.HTTP;
+ case "irc": return SecProtocolType.IRC;
+ case "nntp": return SecProtocolType.NNTP;
+ case "pop3": return SecProtocolType.POP3;
+ case "smtp": return SecProtocolType.SMTP;
+ case "socks": return SecProtocolType.SOCKS;
+ case "imap": return SecProtocolType.IMAP;
+ case "ldap": return SecProtocolType.LDAP;
+ case "appletalk": return SecProtocolType.AppleTalk;
+ case "afp": return SecProtocolType.AFP;
+ case "telnet": return SecProtocolType.Telnet;
+ case "ssh": return SecProtocolType.SSH;
+ case "ftps": return SecProtocolType.FTPS;
+ case "httpproxy": return SecProtocolType.HTTPProxy;
+ case "httpsproxy": return SecProtocolType.HTTPSProxy;
+ case "ftpproxy": return SecProtocolType.FTPProxy;
+ case "cifs": return SecProtocolType.CIFS;
+ case "smb": return SecProtocolType.SMB;
+ case "rtsp": return SecProtocolType.RTSP;
+ case "rtspproxy": return SecProtocolType.RTSPProxy;
+ case "daap": return SecProtocolType.DAAP;
+ case "eppc": return SecProtocolType.EPPC;
+ case "ipp": return SecProtocolType.IPP;
+ case "nntps": return SecProtocolType.NNTPS;
+ case "ldaps": return SecProtocolType.LDAPS;
+ case "telnets": return SecProtocolType.TelnetS;
+ case "imaps": return SecProtocolType.IMAPS;
+ case "ircs": return SecProtocolType.IRCS;
+ case "pop3s": return SecProtocolType.POP3S;
+ case "cvspserver": return SecProtocolType.CVSpserver;
+ case "svn": return SecProtocolType.SVN;
+ default: return SecProtocolType.Any;
+ }
+ }
+
+ public static unsafe void AddInternetPassword (Uri uri, string password)
+ {
+ byte[] path = Encoding.UTF8.GetBytes (string.Join (string.Empty, uri.Segments).Substring (1)); // don't include the leading '/'
+ byte[] user = Encoding.UTF8.GetBytes (Uri.UnescapeDataString (uri.UserInfo));
+ byte[] passwd = Encoding.UTF8.GetBytes (password);
+ byte[] host = Encoding.UTF8.GetBytes (uri.Host);
+ var auth = GetSecAuthenticationType (uri.Query);
+ var protocol = GetSecProtocolType (uri.Scheme);
IntPtr passwordPtr = IntPtr.Zero;
+ IntPtr itemRef = IntPtr.Zero;
uint passwordLength = 0;
- var passwordBytes = System.Text.Encoding.UTF8.GetBytes (password);
+ int port = uri.Port;
// See if there is already a password there for this uri
- var result = SecKeychainFindInternetPassword (IntPtr.Zero, (uint) uri.Host.Length, uri.Host, 0, null,
- (uint) uri.UserInfo.Length, uri.UserInfo, (uint) uri.PathAndQuery.Length, uri.PathAndQuery,
- (ushort) uri.Port, 0, 0, out passwordLength, out passwordPtr, ref itemRef);
+ var result = SecKeychainFindInternetPassword (IntPtr.Zero, (uint) host.Length, host, 0, null,
+ (uint) user.Length, user, (uint) path.Length, path, (ushort) port,
+ protocol, auth, out passwordLength, out passwordPtr, ref itemRef);
+
if (result == OSStatus.Ok) {
// If there is, replace it with the new one
- result = SecKeychainItemModifyAttributesAndData (itemRef, IntPtr.Zero, (uint) passwordBytes.Length, passwordBytes);
+ result = SecKeychainItemModifyAttributesAndData (itemRef, IntPtr.Zero, (uint) passwd.Length, passwd);
+ CFRelease (itemRef);
} else {
// Otherwise add a new entry with the password
- result = SecKeychainAddInternetPassword (IntPtr.Zero, (uint) uri.Host.Length, uri.Host, 0, null,
- (uint) uri.UserInfo.Length, uri.UserInfo, (uint) uri.PathAndQuery.Length, uri.PathAndQuery,
- (ushort) uri.Port, 0, 0, (uint) passwordBytes.Length, passwordBytes, ref itemRef);
+// result = SecKeychainAddInternetPassword (IntPtr.Zero, (uint) uri.Host.Length, uri.Host, 0, null,
+// (uint) user.Length, user, (uint) path.Length, path, (ushort) uri.Port,
+// (int) protocol, (int) auth, (uint) passwordBytes.Length, passwordBytes, ref itemRef);
+
+ var label = Encoding.UTF8.GetBytes (string.Format ("{0} ({1})", uri.Host, Uri.UnescapeDataString (uri.UserInfo)));
+ fixed (byte* labelPtr = label, userPtr = user, hostPtr = host, pathPtr = path) {
+ SecKeychainAttribute* attrs = stackalloc SecKeychainAttribute [7];
+ int* protoPtr = (int*) &protocol;
+ int* authPtr = (int*) &auth;
+ int* portPtr = &port;
+
+ attrs[0] = new SecKeychainAttribute (SecItemAttr.Label, (uint) label.Length, (IntPtr) labelPtr);
+ attrs[1] = new SecKeychainAttribute (SecItemAttr.Account, (uint) user.Length, (IntPtr) userPtr);
+ attrs[2] = new SecKeychainAttribute (SecItemAttr.Protocol, (uint) 4, (IntPtr) protoPtr);
+ attrs[3] = new SecKeychainAttribute (SecItemAttr.AuthType, (uint) 4, (IntPtr) authPtr);
+ attrs[4] = new SecKeychainAttribute (SecItemAttr.Server, (uint) host.Length, (IntPtr) hostPtr);
+ attrs[5] = new SecKeychainAttribute (SecItemAttr.Port, (uint) 4, (IntPtr) portPtr);
+ attrs[6] = new SecKeychainAttribute (SecItemAttr.Path, (uint) path.Length, (IntPtr) pathPtr);
+
+ SecKeychainAttributeList attrList = new SecKeychainAttributeList (6, (IntPtr) attrs);
+
+ itemRef = IntPtr.Zero;
+ result = SecKeychainItemCreateFromContent (SecItemClass.InternetPassword, &attrList, (uint) passwd.Length, passwd, IntPtr.Zero, IntPtr.Zero, ref itemRef);
+ CFRelease (itemRef);
+ }
}
if (result != OSStatus.Ok)
@@ -370,19 +501,35 @@ namespace MonoDevelop.MacInterop
public static string FindInternetPassword (Uri uri)
{
+ byte[] path = Encoding.UTF8.GetBytes (string.Join (string.Empty, uri.Segments).Substring (1)); // don't include the leading '/'
+ byte[] user = Encoding.UTF8.GetBytes (Uri.UnescapeDataString (uri.UserInfo));
+ byte[] host = Encoding.UTF8.GetBytes (uri.Host);
+ var auth = GetSecAuthenticationType (uri.Query);
+ var protocol = GetSecProtocolType (uri.Scheme);
+ IntPtr passwordPtr = IntPtr.Zero;
IntPtr itemRef = IntPtr.Zero;
- IntPtr password = IntPtr.Zero;
uint passwordLength = 0;
- var result = SecKeychainFindInternetPassword (IntPtr.Zero, (uint) uri.Host.Length, uri.Host, 0, null,
- (uint) uri.UserInfo.Length, uri.UserInfo, (uint) uri.PathAndQuery.Length, uri.PathAndQuery,
- (ushort) uri.Port, 0, 0, out passwordLength, out password, ref itemRef);
+
+ // Look for an internet password for the given protocol and auth mechanism
+ var result = SecKeychainFindInternetPassword (IntPtr.Zero, (uint) host.Length, host, 0, null,
+ (uint) user.Length, user, (uint) path.Length, path, (ushort) uri.Port,
+ protocol, auth, out passwordLength, out passwordPtr, ref itemRef);
+
+ // Fall back to looking for a password for SecProtocolType.Any && SecAuthenticationType.Any
+ if (result == OSStatus.ItemNotFound && protocol != SecProtocolType.Any)
+ result = SecKeychainFindInternetPassword (IntPtr.Zero, (uint) host.Length, host, 0, null,
+ (uint) user.Length, user, (uint) path.Length, path, (ushort) uri.Port,
+ 0, auth, out passwordLength, out passwordPtr, ref itemRef);
+
+ CFRelease (itemRef);
+
if (result == OSStatus.ItemNotFound)
return null;
if (result != OSStatus.Ok)
throw new Exception ("Could not find internet password: " + GetError (result));
- return Marshal.PtrToStringAuto (password, (int) passwordLength);
+ return Marshal.PtrToStringAuto (passwordPtr, (int) passwordLength);
}
enum SecItemClass : uint
@@ -395,6 +542,38 @@ namespace MonoDevelop.MacInterop
PrivateKey = 0x0000000A + 6,
SymmetricKey = 0x0000000A + 7
}
+
+ enum SecItemAttr : int
+ {
+ CreationDate = 1667522932,
+ ModDate = 1835295092,
+ Description = 1684370275,
+ Comment = 1768123764,
+ Creator = 1668445298,
+ Type = 1954115685,
+ ScriptCode = 1935897200,
+ Label = 1818321516,
+ Invisible = 1768846953,
+ Negative = 1852139361,
+ CustomIcon = 1668641641,
+ Account = 1633903476,
+ Service = 1937138533,
+ Generic = 1734700641,
+ SecurityDomain = 1935961454,
+ Server = 1936881266,
+ AuthType = 1635023216,
+ Port = 1886351988,
+ Path = 1885434984,
+ Volume = 1986817381,
+ Address = 1633969266,
+ Signature = 1936943463,
+ Protocol = 1886675820,
+ CertificateType = 1668577648,
+ CertificateEncoding = 1667591779,
+ CrlType = 1668445296,
+ CrlEncoding = 1668443747,
+ Alias = 1634494835,
+ }
enum OSStatus
{
@@ -432,6 +611,57 @@ namespace MonoDevelop.MacInterop
Wrap = 25,
Unwrap = 26,
}
+
+ enum SecAuthenticationType : int
+ {
+ NTLM = 1835824238,
+ MSN = 1634628461,
+ DPA = 1633775716,
+ RPA = 1633775730,
+ HTTPBasic = 1886680168,
+ HTTPDigest = 1685353576,
+ HTMLForm = 1836216166,
+ Default = 1953261156,
+ Any = 0
+ }
+
+ enum SecProtocolType : int
+ {
+ FTP = 1718906912,
+ FTPAccount = 1718906977,
+ HTTP = 1752462448,
+ IRC = 1769104160,
+ NNTP = 1852732528,
+ POP3 = 1886351411,
+ SMTP = 1936553072,
+ SOCKS = 1936685088,
+ IMAP = 1768776048,
+ LDAP = 1818517872,
+ AppleTalk = 1635019883,
+ AFP = 1634103328,
+ Telnet = 1952803950,
+ SSH = 1936943136,
+ FTPS = 1718906995,
+ HTTPProxy = 1752461432,
+ HTTPSProxy = 1752462200,
+ FTPProxy = 1718907000,
+ CIFS = 1667851891,
+ SMB = 1936548384,
+ RTSP = 1920234352,
+ RTSPProxy = 1920234360,
+ DAAP = 1684103536,
+ EPPC = 1701867619,
+ IPP = 1768976416,
+ NNTPS = 1853124723,
+ LDAPS = 1818521715,
+ TelnetS = 1952803955,
+ IMAPS = 1768779891,
+ IRCS = 1769104243,
+ POP3S = 1886351475,
+ CVSpserver = 1668707184,
+ SVN = 1937141280,
+ Any = 0
+ }
[Flags]
enum CssmKeyUse : uint