1 // Copyright 2006 Alp Toker <alp@atoker.com>
2 // This software is made available under the MIT License
3 // See COPYING for details
4 
5 //We send BSD-style credentials on all platforms
6 //Doesn't seem to break Linux (but is redundant there)
7 //This may turn out to be a bad idea
8 #define HAVE_CMSGCRED
9 
10 using System;
11 using System.IO;
12 using System.Text;
13 using System.Runtime.InteropServices;
14 using DBus.Unix;
15 using DBus.Protocol;
16 
17 namespace DBus.Transports
18 {
19 	class UnixNativeTransport : UnixTransport
20 	{
21 		internal UnixSocket socket;
22 
AuthString()23 		public override string AuthString ()
24 		{
25 			long uid = Mono.Unix.Native.Syscall.geteuid ();
26 			return uid.ToString ();
27 		}
28 
Open(string path, bool @abstract)29 		public override void Open (string path, bool @abstract)
30 		{
31 			if (String.IsNullOrEmpty (path))
32 				throw new ArgumentException ("path");
33 
34 			if (@abstract)
35 				socket = OpenAbstractUnix (path);
36 			else
37 				socket = OpenUnix (path);
38 
39 			//socket.Blocking = true;
40 			SocketHandle = (long)socket.Handle;
41 			//Stream = new UnixStream ((int)socket.Handle);
42 			Stream = new UnixStream (socket);
43 		}
44 
45 		//send peer credentials null byte
46 		//different platforms do this in different ways
47 #if HAVE_CMSGCRED
WriteBsdCred()48 		unsafe void WriteBsdCred ()
49 		{
50 			//null credentials byte
51 			byte buf = 0;
52 
53 			IOVector iov = new IOVector ();
54 			//iov.Base = (IntPtr)(&buf);
55 			iov.Base = &buf;
56 			iov.Length = 1;
57 
58 			msghdr msg = new msghdr ();
59 			msg.msg_iov = &iov;
60 			msg.msg_iovlen = 1;
61 
62 			cmsg cm = new cmsg ();
63 			msg.msg_control = (IntPtr)(&cm);
64 			msg.msg_controllen = (uint)sizeof (cmsg);
65 			cm.hdr.cmsg_len = (uint)sizeof (cmsg);
66 			cm.hdr.cmsg_level = 0xffff; //SOL_SOCKET
67 			cm.hdr.cmsg_type = 0x03; //SCM_CREDS
68 
69 			int written = socket.SendMsg (&msg, 0);
70 			if (written != 1)
71 				throw new Exception ("Failed to write credentials");
72 		}
73 #endif
74 
WriteCred()75 		public override void WriteCred ()
76 		{
77 #if HAVE_CMSGCRED
78 			try {
79 				WriteBsdCred ();
80 				return;
81 			} catch {
82 				if (ProtocolInformation.Verbose)
83 					Console.Error.WriteLine ("Warning: WriteBsdCred() failed; falling back to ordinary WriteCred()");
84 			}
85 #endif
86 			//null credentials byte
87 			byte buf = 0;
88 			Stream.WriteByte (buf);
89 		}
90 
GetSockAddr(string path)91 		public static byte[] GetSockAddr (string path)
92 		{
93 			byte[] p = Encoding.Default.GetBytes (path);
94 
95 			byte[] sa = new byte[2 + p.Length + 1];
96 
97 			sa[0] = (byte) sa.Length;
98 			sa[1] = 1; /* AF_UNIX */
99 
100 			for (int i = 0 ; i != p.Length ; i++)
101 				sa[2 + i] = p[i];
102 			sa[2 + p.Length] = 0; //null suffix for domain socket addresses, see unix(7)
103 
104 			return sa;
105 		}
106 
GetSockAddrAbstract(string path)107 		public static byte[] GetSockAddrAbstract (string path)
108 		{
109 			byte[] p = Encoding.Default.GetBytes (path);
110 
111 			byte[] sa = new byte[2 + 1 + p.Length];
112 
113 			sa[0] = (byte) sa.Length;
114 			sa[1] = 1; /* AF_UNIX */
115 
116 			sa[2] = 0; //null prefix for abstract domain socket addresses, see unix(7)
117 			for (int i = 0 ; i != p.Length ; i++)
118 				sa[3 + i] = p[i];
119 
120 			return sa;
121 		}
122 
OpenUnix(string path)123 		internal UnixSocket OpenUnix (string path)
124 		{
125 			byte[] sa = GetSockAddr (path);
126 			UnixSocket client = new UnixSocket ();
127 			client.Connect (sa);
128 			return client;
129 		}
130 
OpenAbstractUnix(string path)131 		internal UnixSocket OpenAbstractUnix (string path)
132 		{
133 			byte[] sa = GetSockAddrAbstract (path);
134 			UnixSocket client = new UnixSocket ();
135 			client.Connect (sa);
136 			return client;
137 		}
138 	}
139 
140 #if HAVE_CMSGCRED
141 	unsafe struct msghdr
142 	{
143 		public IntPtr msg_name; //optional address
144 		public uint msg_namelen; //size of address
145 		public IOVector *msg_iov; //scatter/gather array
146 		public int msg_iovlen; //# elements in msg_iov
147 		public IntPtr msg_control; //ancillary data, see below
148 		public uint msg_controllen; //ancillary data buffer len
149 		public int msg_flags; //flags on received message
150 	}
151 
152 	struct cmsghdr
153 	{
154 		public uint cmsg_len; //data byte count, including header
155 		public int cmsg_level; //originating protocol
156 		public int cmsg_type; //protocol-specific type
157 	}
158 
159 	unsafe struct cmsgcred
160 	{
161 		const int CMGROUP_MAX = 16;
162 
163 		public int cmcred_pid; //PID of sending process
164 		public uint cmcred_uid; //real UID of sending process
165 		public uint cmcred_euid; //effective UID of sending process
166 		public uint cmcred_gid; //real GID of sending process
167 		public short cmcred_ngroups; //number or groups
168 		public fixed uint cmcred_groups[CMGROUP_MAX]; //groups
169 	}
170 
171 	struct cmsg
172 	{
173 		public cmsghdr hdr;
174 		public cmsgcred cred;
175 	}
176 #endif
177 }
178