]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/hw/vnc/auth.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / programs / Xserver / hw / vnc / auth.c
1 /*
2  * auth.c - deal with authentication.
3  *
4  * This file implements the VNC authentication protocol when setting up an RFB
5  * connection.
6  */
7
8 /*
9  *  Copyright (C) 2002 RealVNC Ltd.
10  *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
11  *
12  *  This is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This software is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this software; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
25  *  USA.
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include "windowstr.h"
31 #include "rfb.h"
32
33
34 #define MAX_AUTH_TRIES 5
35 #define AUTH_TOO_MANY_BASE_DELAY 10 * 1000 /* in ms, doubles for each failure
36                                               over MAX_AUTH_TRIES */
37
38 static int rfbAuthFailure();
39 static CARD32 rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg);
40
41 char *rfbAuthPasswdFile = NULL;
42 int rfbAuthTries = 0;
43 Bool rfbAuthTooManyTries = FALSE;
44 static OsTimerPtr timer = NULL;
45
46
47 /*
48  * rfbAuthNewClient is called when we reach the point of authenticating
49  * a new client.  If authentication isn't being used then we simply send
50  * rfbNoAuth.  Otherwise we send rfbVncAuth plus the challenge.
51  */
52
53 void
54 rfbAuthNewClient(cl)
55     rfbClientPtr cl;
56 {
57     char buf[4 + CHALLENGESIZE];
58     int len;
59
60     cl->state = RFB_AUTHENTICATION;
61
62     if (rfbAuthPasswdFile && !cl->reverseConnection) {
63
64         if (rfbAuthTooManyTries) {
65             rfbClientConnFailed(cl, "Too many authentication failures");
66             return;
67         }
68
69         *(CARD32 *)buf = Swap32IfLE(rfbVncAuth);
70         vncRandomBytes(cl->authChallenge);
71         memcpy(&buf[4], (char *)cl->authChallenge, CHALLENGESIZE);
72         len = 4 + CHALLENGESIZE;
73
74     } else {
75
76         *(CARD32 *)buf = Swap32IfLE(rfbNoAuth);
77         len = 4;
78         cl->state = RFB_INITIALISATION;
79     }
80
81     if (WriteExact(cl->sock, buf, len) < 0) {
82         rfbLogPerror("rfbAuthNewClient: write");
83         rfbCloseSock(cl->sock);
84         return;
85     }
86 }
87
88
89 /*
90  * rfbAuthProcessClientMessage is called when the client sends its
91  * authentication response.
92  */
93
94 void
95 rfbAuthProcessClientMessage(cl)
96     rfbClientPtr cl;
97 {
98     char *passwd;
99     int i, n;
100     CARD8 response[CHALLENGESIZE];
101     CARD32 authResult;
102
103     n = ReadExact(cl->sock, (char *)response, CHALLENGESIZE);
104
105     if (n <= 0) {
106         if (n == 0)
107             rfbLog("rfbAuthProcessClientMessage: read failed\n");
108         else
109             rfbLogPerror("rfbAuthProcessClientMessage: read");
110         rfbAuthFailure();
111         rfbCloseSock(cl->sock);
112         return;
113     }
114
115     passwd = vncDecryptPasswdFromFile(rfbAuthPasswdFile);
116
117     if (passwd == NULL) {
118         rfbLog("rfbAuthProcessClientMessage: could not get password from %s\n",
119                rfbAuthPasswdFile);
120
121         authResult = Swap32IfLE(rfbVncAuthFailed);
122
123         if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
124             rfbLogPerror("rfbAuthProcessClientMessage: write");
125         }
126         rfbCloseSock(cl->sock);
127         return;
128     }
129
130     vncEncryptBytes(cl->authChallenge, passwd);
131
132     /* Lose the password from memory */
133     for (i = strlen(passwd); i >= 0; i--) {
134         passwd[i] = '\0';
135     }
136
137     free((char *)passwd);
138
139     if (memcmp(cl->authChallenge, response, CHALLENGESIZE) != 0) {
140         rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n",
141                cl->host);
142
143         authResult = rfbAuthFailure();
144         authResult = Swap32IfLE(authResult);
145
146         if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
147             rfbLogPerror("rfbAuthProcessClientMessage: write");
148         }
149         rfbCloseSock(cl->sock);
150         return;
151     }
152
153     rfbAuthTries = 0;
154
155     authResult = Swap32IfLE(rfbVncAuthOK);
156
157     if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
158         rfbLogPerror("rfbAuthProcessClientMessage: write");
159         rfbCloseSock(cl->sock);
160         return;
161     }
162
163     cl->state = RFB_INITIALISATION;
164 }
165
166
167 static int rfbAuthFailure()
168 {
169   int i;
170
171   rfbAuthTries++;
172
173   if (rfbAuthTries >= MAX_AUTH_TRIES) {
174
175     CARD32 delay = AUTH_TOO_MANY_BASE_DELAY;
176     for (i = MAX_AUTH_TRIES; i < rfbAuthTries; i++)
177       delay *= 2;
178     timer = TimerSet(timer, 0, delay, rfbAuthReenable, NULL);
179
180     rfbAuthTooManyTries = TRUE;
181     return rfbVncAuthTooMany;
182   }
183
184   return rfbVncAuthFailed;
185 }
186
187
188 static CARD32
189 rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg)
190 {
191     rfbAuthTooManyTries = FALSE;
192     return 0;
193 }