1 /******************************************************************************
2 
3 
4 Copyright 1993, 1998  The Open Group
5 
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation.
11 
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 Except as contained in this notice, the name of The Open Group shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from The Open Group.
25 
26 Author: Ralph Mor, X Consortium
27 ******************************************************************************/
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 #include <X11/ICE/ICElib.h>
33 #include "ICElibint.h"
34 #include <X11/ICE/ICEutil.h>
35 
36 #include <time.h>
37 
38 #ifdef HAVE_LIBBSD
39 #include <bsd/stdlib.h>	/* for arc4random_buf() */
40 #endif
41 
42 #include <unistd.h>
43 
44 static int was_called_state;
45 
46 #ifndef HAVE_ARC4RANDOM_BUF
47 
48 static void
emulate_getrandom_buf(char * auth,int len)49 emulate_getrandom_buf (
50 	char *auth,
51 	int len
52 )
53 {
54     long    ldata[2];
55     int	    seed;
56     int	    value;
57     int	    i;
58 
59 #ifdef ITIMER_REAL
60     {
61 	struct timeval  now;
62 	X_GETTIMEOFDAY (&now);
63 	ldata[0] = now.tv_sec;
64 	ldata[1] = now.tv_usec;
65     }
66 #else /* ITIMER_REAL */
67     {
68 	long    time ();
69 	ldata[0] = time ((long *) 0);
70 	ldata[1] = getpid ();
71     }
72 #endif /* ITIMER_REAL */
73     seed = (ldata[0]) + (ldata[1] << 16);
74     srand (seed);
75     for (i = 0; i < len; i++)
76     {
77 	value = rand ();
78 	auth[i] = value & 0xff;
79     }
80 }
81 
82 static void
arc4random_buf(char * auth,int len)83 arc4random_buf (
84 	char *auth,
85 	int len
86 )
87 {
88 #if HAVE_GETENTROPY
89     int	    ret;
90 
91     /* weak emulation of arc4random through the entropy libc */
92     ret = getentropy (auth, len);
93     if (ret == 0)
94 	return;
95 #endif /* HAVE_GETENTROPY */
96 
97     emulate_getrandom_buf (auth, len);
98 }
99 
100 #endif /* !defined(HAVE_ARC4RANDOM_BUF) */
101 
102 /*
103  * MIT-MAGIC-COOKIE-1 is a sample authentication method implemented by
104  * the SI.  It is not part of standard ICElib.
105  */
106 
107 
108 char *
IceGenerateMagicCookie(int len)109 IceGenerateMagicCookie (
110 	int len
111 )
112 {
113     char    *auth;
114 
115     if ((auth = malloc (len + 1)) == NULL)
116 	return (NULL);
117 
118     arc4random_buf (auth, len);
119 
120     auth[len] = '\0';
121     return (auth);
122 }
123 
124 
125 
126 IcePoAuthStatus
_IcePoMagicCookie1Proc(IceConn iceConn,IcePointer * authStatePtr,Bool cleanUp,Bool swap,int authDataLen,IcePointer authData,int * replyDataLenRet,IcePointer * replyDataRet,char ** errorStringRet)127 _IcePoMagicCookie1Proc (
128 	IceConn		iceConn,
129 	IcePointer	*authStatePtr,
130 	Bool 		cleanUp,
131 	Bool		swap,
132 	int     	authDataLen,
133 	IcePointer	authData,
134 	int 		*replyDataLenRet,
135 	IcePointer	*replyDataRet,
136 	char    	**errorStringRet
137 )
138 {
139     if (cleanUp)
140     {
141 	/*
142 	 * We didn't allocate any state.  We're done.
143 	 */
144 
145 	return (IcePoAuthDoneCleanup);
146     }
147 
148     *errorStringRet = NULL;
149 
150     if (*authStatePtr == NULL)
151     {
152 	/*
153 	 * This is the first time we're being called.  Search the
154 	 * authentication data for the first occurence of
155 	 * MIT-MAGIC-COOKIE-1 that matches iceConn->connection_string.
156 	 */
157 
158 	unsigned short  length;
159 	char		*data;
160 
161 	_IceGetPoAuthData ("ICE", iceConn->connection_string,
162 	    "MIT-MAGIC-COOKIE-1", &length, &data);
163 
164 	if (!data)
165 	{
166 	    const char *tempstr =
167 		"Could not find correct MIT-MAGIC-COOKIE-1 authentication";
168 
169 	    *errorStringRet = strdup(tempstr);
170 
171 	    return (IcePoAuthFailed);
172 	}
173 	else
174 	{
175 	    *authStatePtr = (IcePointer) &was_called_state;
176 
177 	    *replyDataLenRet = length;
178 	    *replyDataRet = data;
179 
180 	    return (IcePoAuthHaveReply);
181 	}
182     }
183     else
184     {
185 	/*
186 	 * We should never get here for MIT-MAGIC-COOKIE-1 since it is
187 	 * a single pass authentication method.
188 	 */
189 
190 	const char *tempstr =
191 	    "MIT-MAGIC-COOKIE-1 authentication internal error";
192 
193 	*errorStringRet = strdup(tempstr);
194 
195 	return (IcePoAuthFailed);
196     }
197 }
198 
199 IcePoAuthProc	_IcePoAuthProcs[] = {_IcePoMagicCookie1Proc};
200 
201 
202 IcePaAuthStatus
_IcePaMagicCookie1Proc(IceConn iceConn,IcePointer * authStatePtr,Bool swap,int authDataLen,IcePointer authData,int * replyDataLenRet,IcePointer * replyDataRet,char ** errorStringRet)203 _IcePaMagicCookie1Proc (
204 	IceConn		iceConn,
205 	IcePointer	*authStatePtr,
206 	Bool		swap,
207 	int     	authDataLen,
208 	IcePointer	authData,
209 	int 		*replyDataLenRet,
210 	IcePointer	*replyDataRet,
211 	char    	**errorStringRet
212 )
213 {
214     *errorStringRet = NULL;
215     *replyDataLenRet = 0;
216     *replyDataRet = NULL;
217 
218     if (*authStatePtr == NULL)
219     {
220 	/*
221 	 * This is the first time we're being called.  We don't have
222 	 * any data to pass to the other client.
223 	 */
224 
225 	*authStatePtr = (IcePointer) &was_called_state;
226 
227 	return (IcePaAuthContinue);
228     }
229     else
230     {
231 	/*
232 	 * Search the authentication data for the first occurence of
233 	 * MIT-MAGIC-COOKIE-1 that matches iceConn->connection_string.
234 	 */
235 
236 	unsigned short  length;
237 	char		*data;
238 
239 	_IceGetPaAuthData ("ICE", iceConn->connection_string,
240 	    "MIT-MAGIC-COOKIE-1", &length, &data);
241 
242 	if (data)
243 	{
244 	    IcePaAuthStatus stat;
245 
246 	    if (authDataLen == length &&
247 	        memcmp (authData, data, authDataLen) == 0)
248 	    {
249 		stat = IcePaAuthAccepted;
250 	    }
251 	    else
252 	    {
253 		const char *tempstr
254 		    = "MIT-MAGIC-COOKIE-1 authentication rejected";
255 
256 		*errorStringRet = strdup(tempstr);
257 
258 		stat = IcePaAuthRejected;
259 	    }
260 
261 	    free (data);
262 	    return (stat);
263 	}
264 	else
265 	{
266 	    /*
267 	     * We should never get here because in the ConnectionReply
268 	     * we should have passed all the valid methods.  So we should
269 	     * always find a valid entry.
270 	     */
271 
272 	    const char *tempstr =
273 		"MIT-MAGIC-COOKIE-1 authentication internal error";
274 
275 	    *errorStringRet = strdup(tempstr);
276 
277 	    return (IcePaAuthFailed);
278 	}
279     }
280 }
281 
282 IcePaAuthProc	_IcePaAuthProcs[] = {_IcePaMagicCookie1Proc};
283