// // Gnome.Keyring.Ring.cs // // Authors: // Gonzalo Paniagua Javier (gonzalo@ximian.com) // Alp Toker (alp@atoker.com) // // (C) Copyright 2006 Novell, Inc. (http://www.novell.com) // (C) Copyright 2007 Alp Toker // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.IO; using System.Net; using System.Net.Sockets; using System.Reflection; using Mono.Unix; #if WITH_DBUS using NDesk.DBus; #endif namespace Gnome.Keyring { public class Ring { static string appname; private Ring () { } public static string ApplicationName { get { if (appname == null) { Assembly assembly = Assembly.GetEntryAssembly (); if (assembly == null) throw new Exception ("You need to set Ring.ApplicationName."); appname = assembly.GetName ().Name; } return appname; } set { if (value == null || value == "") throw new ArgumentException ("Cannot be null or empty", "value"); appname = value; } } public static bool Available { get { Socket sock = Connect (); if (sock != null) { sock.Close (); return true; } return false; } } static Socket Connect () { string filename; Socket sock; filename = Environment.GetEnvironmentVariable ("GNOME_KEYRING_SOCKET"); sock = Connect (filename); #if WITH_DBUS if (sock == null) { try { filename = Bus.Session.GetObject ("org.gnome.keyring", new ObjectPath ("/org/gnome/keyring/daemon")).GetSocketPath (); } catch (Exception) { filename = null; } sock = Connect (filename); } #endif return sock; } static Socket Connect (string filename) { if (filename == null || filename == "") return null; EndPoint ep = new UnixEndPoint (filename); Socket sock = new Socket (AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); try { sock.Connect (ep); } catch (Exception) { sock.Close (); return null; } return sock; } static int GetInt32 (Socket sock) { byte [] cuatro = new byte [4]; if (sock.Receive (cuatro) != 4) throw new KeyringException (ResultCode.IOError); return (cuatro [3] + (cuatro [2] << 8) + (cuatro [1] << 16) + (cuatro [0] << 24)); } static byte [] one = new byte [1]; static ResponseMessage SendRequest (MemoryStream stream) { Socket sock = Connect (); if (sock == null) throw new KeyringException (ResultCode.NoKeyringDaemon); try { sock.Send (one); // Credentials byte byte [] buffer = stream.ToArray (); sock.Send (buffer); int packet_size = GetInt32 (sock) - 4; if (packet_size < 0) throw new KeyringException (ResultCode.IOError); byte [] response = new byte [packet_size]; int nbytes = sock.Receive (response); if (nbytes != response.Length) throw new KeyringException (ResultCode.IOError); ResponseMessage resp = new ResponseMessage (response); ResultCode result = (ResultCode) resp.GetInt32 (); if (result != 0) throw new KeyringException (result); return resp; } finally { sock.Close (); } } public static void LockAll () { RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.LockAll); SendRequest (req.Stream); } public static void SetDefaultKeyring (string newKeyring) { if (newKeyring == null) throw new ArgumentNullException ("newKeyring"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.SetDefaultKeyring, newKeyring); SendRequest (req.Stream); } public static string GetDefaultKeyring () { RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.GetDefaultKeyring); ResponseMessage resp = SendRequest (req.Stream); return resp.GetString (); } public static string [] GetKeyrings () { RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.ListKeyrings); ResponseMessage resp = SendRequest (req.Stream); return resp.GetStringList (); } public static void CreateKeyring (string name, string password) { RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.CreateKeyring, name, password); SendRequest (req.Stream); } public static void Lock (string keyring) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.LockKeyring, keyring); SendRequest (req.Stream); } public static void Unlock (string keyring, string password) { if (keyring == null) throw new ArgumentNullException ("keyring"); if (password == null) throw new ArgumentNullException ("password"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.UnlockKeyring, keyring, password); try { SendRequest (req.Stream); } catch (KeyringException ke) { if (ke.ResultCode != ResultCode.AlreadyUnlocked) throw; } } public static void DeleteKeyring (string keyring) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.DeleteKeyring, keyring); SendRequest (req.Stream); } public static int [] ListItemIDs (string keyring) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.ListItems, keyring); ResponseMessage resp = SendRequest (req.Stream); int len = resp.GetInt32 (); int [] result = new int [len]; for (int i = 0; i < len; i++) { result [i] = resp.GetInt32 (); } return result; } static ItemData [] empty_item_data = new ItemData [0]; public static ItemData [] Find (ItemType type, Hashtable atts) { if (atts == null) throw new ArgumentNullException ("atts"); RequestMessage req = new RequestMessage (); req.StartOperation (Operation.Find); req.Write ((int) type); req.WriteAttributes (atts); req.EndOperation (); ResponseMessage resp = null; try { resp = SendRequest (req.Stream); } catch (KeyringException ke) { if (ke.ResultCode == ResultCode.Denied) return empty_item_data; throw; } ArrayList list = new ArrayList (); while (resp.DataAvailable) { ItemData found = ItemData.GetInstanceFromItemType (type); found.Keyring = resp.GetString (); found.ItemID = resp.GetInt32 (); found.Secret = resp.GetString (); found.Attributes = new Hashtable (); resp.ReadAttributes (found.Attributes); found.SetValuesFromAttributes (); list.Add (found); } return (ItemData []) list.ToArray (typeof (ItemData)); } static NetItemData [] empty_net_item_data = new NetItemData [0]; public static NetItemData [] FindNetworkPassword (string user, string domain, string server, string obj, string protocol, string authtype, int port) { RequestMessage req = new RequestMessage (); req.StartOperation (Operation.Find); req.Write ((int) ItemType.NetworkPassword); Hashtable tbl = new Hashtable (); tbl ["user"] = user; tbl ["domain"] = domain; tbl ["server"] = server; tbl ["object"] = obj; tbl ["protocol"] = protocol; tbl ["authtype"] = authtype; if (port != 0) tbl ["port"] = port; req.WriteAttributes (tbl); req.EndOperation (); ResponseMessage resp = null; try { resp = SendRequest (req.Stream); } catch (KeyringException ke) { if (ke.ResultCode == ResultCode.Denied) return empty_net_item_data; throw; } ArrayList list = new ArrayList (); while (resp.DataAvailable) { NetItemData found = new NetItemData (); found.Keyring = resp.GetString (); found.ItemID = resp.GetInt32 (); found.Secret = resp.GetString (); found.Attributes = new Hashtable (); resp.ReadAttributes (found.Attributes); found.SetValuesFromAttributes (); list.Add (found); } return (NetItemData []) list.ToArray (typeof (NetItemData)); } public static int CreateItem (string keyring, ItemType type, string displayName, Hashtable attributes, string secret, bool updateIfExists) { RequestMessage req = new RequestMessage (); req.StartOperation (Operation.CreateItem); req.Write (keyring); req.Write (displayName); req.Write (secret); req.WriteAttributes (attributes); req.Write ((int) type); req.Write (updateIfExists ? 1 : 0); req.EndOperation (); ResponseMessage resp = SendRequest (req.Stream); return resp.GetInt32 (); } public static void DeleteItem (string keyring, int id) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.DeleteItem, keyring, id); SendRequest (req.Stream); } public static int CreateOrModifyNetworkPassword (string keyring, string user, string domain, string server, string obj, string protocol, string authtype, int port, string password) { Hashtable tbl = new Hashtable (); tbl ["user"] = user; tbl ["domain"] = domain; tbl ["server"] = server; tbl ["object"] = obj; tbl ["protocol"] = protocol; tbl ["authtype"] = authtype; if (port != 0) tbl ["port"] = port; string display_name; if (port != 0) display_name = String.Format ("{0}@{1}:{3}/{2}", user, server, obj, port); else display_name = String.Format ("{0}@{1}/{2}", user, server, obj); return CreateItem (keyring, ItemType.NetworkPassword, display_name, tbl, password, true); } public static ItemData GetItemInfo (string keyring, int id) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.GetItemInfo, keyring, id); ResponseMessage resp = SendRequest (req.Stream); ItemType itype = (ItemType) resp.GetInt32 (); ItemData item = ItemData.GetInstanceFromItemType (itype); string name = resp.GetString (); string secret = resp.GetString (); DateTime mtime = resp.GetDateTime (); DateTime ctime = resp.GetDateTime (); item.Keyring = keyring; item.ItemID = id; item.Secret = secret; Hashtable tbl = new Hashtable (); tbl ["name"] = name; tbl ["keyring_ctime"] = ctime; tbl ["keyring_mtime"] = mtime; item.Attributes = tbl; item.SetValuesFromAttributes (); return item; } public static void SetItemInfo (string keyring, int id, ItemType type, string displayName, string secret) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.StartOperation (Operation.SetItemInfo); req.Write (keyring); req.Write (id); req.Write ((int) type); req.Write (displayName); req.Write (secret); req.EndOperation (); SendRequest (req.Stream); } public static Hashtable GetItemAttributes (string keyring, int id) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.GetItemAttributes, keyring, id); ResponseMessage resp = SendRequest (req.Stream); Hashtable tbl = new Hashtable (); resp.ReadAttributes (tbl); return tbl; } public static void SetItemAttributes (string keyring, int id, Hashtable atts) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.StartOperation (Operation.SetItemAttributes); req.Write (keyring); req.Write (id); req.WriteAttributes (atts); req.EndOperation (); SendRequest (req.Stream); } public static KeyringInfo GetKeyringInfo (string keyring) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.GetKeyringInfo, keyring); ResponseMessage resp = SendRequest (req.Stream); return new KeyringInfo (keyring, (resp.GetInt32 () != 0), resp.GetInt32 (), resp.GetDateTime (), resp.GetDateTime (), (resp.GetInt32 () != 0)); } public static void SetKeyringInfo (string keyring, KeyringInfo info) { if (keyring == null) throw new ArgumentNullException ("keyring"); if (info == null) throw new ArgumentNullException ("info"); RequestMessage req = new RequestMessage (); req.StartOperation (Operation.SetKeyringInfo); req.Write (keyring); req.Write (info.LockOnIdle ? 1 : 0); req.Write (info.LockTimeoutSeconds); req.EndOperation (); SendRequest (req.Stream); } public static ArrayList GetItemACL (string keyring, int id) { if (keyring == null) throw new ArgumentNullException ("keyring"); RequestMessage req = new RequestMessage (); req.CreateSimpleOperation (Operation.GetItemACL, keyring, id); ResponseMessage resp = SendRequest (req.Stream); int count = resp.GetInt32 (); ArrayList list = new ArrayList (count); for (int i = 0; i < count; i++) { list.Add (new ItemACL (resp.GetString (), resp.GetString (), (AccessRights) resp.GetInt32 ())); } return list; } public static void SetItemACL (string keyring, int id, ICollection acls) { if (acls == null) throw new ArgumentNullException ("acls"); ItemACL [] arr = new ItemACL [acls.Count]; acls.CopyTo (arr, 0); SetItemACL (keyring, id, arr); } public static void SetItemACL (string keyring, int id, ItemACL [] acls) { if (keyring == null) throw new ArgumentNullException ("keyring"); if (acls == null) throw new ArgumentNullException ("acls"); if (acls.Length == 0) throw new ArgumentException ("Empty ACL set.", "acls"); RequestMessage req = new RequestMessage (); req.StartOperation (Operation.SetItemACL); req.Write (keyring); req.Write (id); req.Write (acls.Length); foreach (ItemACL acl in acls) { req.Write (acl.DisplayName); req.Write (acl.FullPath); req.Write ((int) acl.Access); } req.EndOperation (); SendRequest (req.Stream); } } #if WITH_DBUS [Interface ("org.gnome.keyring.Daemon")] interface IDaemon { string GetSocketPath (); } #endif }