Freeciv-3.2: /fast/freeciv/nightly/S3_2/server/auth.c Source File

Freeciv-3.2

Loading...
Searching...
No Matches
auth.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2005 - M.C. Kaufman
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22/* utility */
23#include "fcintl.h"
24#include "log.h"
25#include "md5.h"
26#include "registry.h"
27#include "shared.h"
28#include "support.h"
29
30/* common */
31#include "connection.h"
32#include "packets.h"
33
34/* common/scripting */
35#include "luascript_types.h"
36
37/* server */
38#include "connecthand.h"
39#include "fcdb.h"
40#include "notify.h"
41#include "sernet.h"
42#include "srv_main.h"
43
44/* server/scripting */
45#include "script_fcdb.h"
46
47#include "auth.h"
48
49#define GUEST_NAME "guest"
50
51#define MIN_PASSWORD_LEN 6 /* minimum length of password */
52#define MIN_PASSWORD_CAPS 0 /* minimum number of capital letters required */
53#define MIN_PASSWORD_NUMS 0 /* minimum number of numbers required */
54
55#define MAX_AUTH_TRIES 3
56#define MAX_WAIT_TIME 300 /* max time we'll wait on a password */
57
58/* after each wrong guess for a password, the server waits this
59 * many seconds to reply to the client */
60 static const int auth_fail_wait[] = { 1, 1, 2, 3 };
61
62static bool is_guest_name(const char *name);
63static void get_unique_guest_name(char *name);
64static bool is_good_password(const char *password, char *msg);
65
66/************************************************************************/
73 bool auth_user(struct connection *pconn, char *username)
74{
75 char tmpname[MAX_LEN_NAME] = "\0";
76
77 /* Assign the client a unique guest name/Reject if guests aren't allowed */
78 if (is_guest_name(username)) {
79 if (srvarg.auth_allow_guests) {
80
81 sz_strlcpy(tmpname, username);
82 get_unique_guest_name(username);
83
84 if (fc_strncmp(tmpname, username, MAX_LEN_NAME)) {
85 notify_conn_early(pconn->self, NULL, E_CONNECTION, ftc_warning,
86 _("Warning: the guest name '%s' has been "
87 "taken, renaming to user '%s'."), tmpname, username);
88 }
89 sz_strlcpy(pconn->username, username);
90 establish_new_connection(pconn);
91 } else {
92 reject_new_connection(_("Guests are not allowed on this server. "
93 "Sorry."), pconn);
94 log_normal(_("%s was rejected: Guests not allowed."), username);
95 return FALSE;
96 }
97 } else {
98 /* We are not a guest, we need an extra check as to whether a
99 * connection can be established: the client must authenticate itself */
100 char buffer[MAX_LEN_MSG];
101 bool exists = FALSE;
102
103 sz_strlcpy(pconn->username, username);
104
105 if (!script_fcdb_call("user_exists", pconn, &exists)) {
106 if (srvarg.auth_allow_guests) {
107 sz_strlcpy(tmpname, pconn->username);
108 get_unique_guest_name(tmpname); /* don't pass pconn->username here */
109 sz_strlcpy(pconn->username, tmpname);
110
111 log_error("Error reading database; connection -> guest");
112 notify_conn_early(pconn->self, NULL, E_CONNECTION, ftc_warning,
113 _("There was an error reading the user "
114 "database, logging in as guest connection '%s'."),
115 pconn->username);
116 establish_new_connection(pconn);
117 } else {
118 reject_new_connection(_("There was an error reading the user database "
119 "and guest logins are not allowed. Sorry"),
120 pconn);
121 log_normal(_("%s was rejected: Database error and guests not "
122 "allowed."), pconn->username);
123 return FALSE;
124 }
125 } else if (exists) {
126 /* we found a user */
127 fc_snprintf(buffer, sizeof(buffer), _("Enter password for %s:"),
128 pconn->username);
129 dsend_packet_authentication_req(pconn, AUTH_LOGIN_FIRST, buffer);
130 pconn->server.auth_settime = time(NULL);
131 pconn->server.status = AS_REQUESTING_OLD_PASS;
132 } else {
133 /* we couldn't find the user, they are new */
134 if (srvarg.auth_allow_newusers) {
135 /* TRANS: Try not to make the translation much longer than the original. */
136 sz_strlcpy(buffer, _("First time login. Set a new password and confirm it."));
137 dsend_packet_authentication_req(pconn, AUTH_NEWUSER_FIRST, buffer);
138 pconn->server.auth_settime = time(NULL);
139 pconn->server.status = AS_REQUESTING_NEW_PASS;
140 } else {
141 reject_new_connection(_("This server allows only preregistered "
142 "users. Sorry."), pconn);
143 log_normal(_("%s was rejected: Only preregistered users allowed."),
144 pconn->username);
145
146 return FALSE;
147 }
148 }
149 }
150 return TRUE;
151}
152
153/************************************************************************/
156 bool auth_handle_reply(struct connection *pconn, char *password)
157{
158 char msg[MAX_LEN_MSG];
159
160 if (pconn->server.status == AS_REQUESTING_NEW_PASS) {
161
162 /* check if the new password is acceptable */
163 if (!is_good_password(password, msg)) {
164 if (pconn->server.auth_tries++ >= MAX_AUTH_TRIES) {
165 reject_new_connection(_("Sorry, too many wrong tries..."), pconn);
166 log_normal(_("%s was rejected: Too many wrong password "
167 "verifies for new user."), pconn->username);
168
169 return FALSE;
170 } else {
171 dsend_packet_authentication_req(pconn, AUTH_NEWUSER_RETRY, msg);
172 return TRUE;
173 }
174 }
175
176 if (!script_fcdb_call("user_save", pconn, password)) {
177 notify_conn(pconn->self, NULL, E_CONNECTION, ftc_warning,
178 _("Warning: There was an error in saving to the database. "
179 "Continuing, but your stats will not be saved."));
180 log_error("Error writing to database for: %s", pconn->username);
181 }
182
183 establish_new_connection(pconn);
184 } else if (pconn->server.status == AS_REQUESTING_OLD_PASS) {
185 bool success = FALSE;
186
187 if (script_fcdb_call("user_verify", pconn, password, &success)
188 && success) {
189 establish_new_connection(pconn);
190 } else {
191 pconn->server.status = AS_FAILED;
192 pconn->server.auth_tries++;
193 pconn->server.auth_settime = time(NULL)
194 + auth_fail_wait[pconn->server.auth_tries];
195 }
196 } else {
197 log_verbose("%s is sending unrequested auth packets", pconn->username);
198 return FALSE;
199 }
200
201 return TRUE;
202}
203
204/************************************************************************/
207 void auth_process_status(struct connection *pconn)
208{
209 switch (pconn->server.status) {
210 case AS_NOT_ESTABLISHED:
211 /* nothing, we're not ready to do anything here yet. */
212 break;
213 case AS_FAILED:
214 /* the connection gave the wrong password, we kick 'em off or
215 * we're throttling the connection to avoid password guessing */
216 if (pconn->server.auth_settime > 0
217 && time(NULL) >= pconn->server.auth_settime) {
218
219 if (pconn->server.auth_tries >= MAX_AUTH_TRIES) {
220 pconn->server.status = AS_NOT_ESTABLISHED;
221 reject_new_connection(_("Sorry, too many wrong tries..."), pconn);
222 log_normal(_("%s was rejected: Too many wrong password tries."),
223 pconn->username);
224 connection_close_server(pconn, _("auth failed"));
225 } else {
226 struct packet_authentication_req request;
227
228 pconn->server.status = AS_REQUESTING_OLD_PASS;
229 request.type = AUTH_LOGIN_RETRY;
230 sz_strlcpy(request.message,
231 _("Your password is incorrect. Try again."));
232 send_packet_authentication_req(pconn, &request);
233 }
234 }
235 break;
236 case AS_REQUESTING_OLD_PASS:
237 case AS_REQUESTING_NEW_PASS:
238 /* waiting on the client to send us a password... don't wait too long */
239 if (time(NULL) >= pconn->server.auth_settime + MAX_WAIT_TIME) {
240 pconn->server.status = AS_NOT_ESTABLISHED;
241 reject_new_connection(_("Sorry, your connection timed out..."), pconn);
242 log_normal(_("%s was rejected: Connection timeout waiting for "
243 "password."), pconn->username);
244 connection_close_server(pconn, _("auth failed"));
245 }
246 break;
247 case AS_ESTABLISHED:
248 /* this better fail bigtime */
249 fc_assert(pconn->server.status != AS_ESTABLISHED);
250 break;
251 }
252}
253
254/************************************************************************/
257 static bool is_guest_name(const char *name)
258{
259 return (fc_strncasecmp(name, GUEST_NAME, strlen(GUEST_NAME)) == 0);
260}
261
262/************************************************************************/
266 static void get_unique_guest_name(char *name)
267{
268 unsigned int i;
269
270 /* first see if the given name is suitable */
271 if (is_guest_name(name) && !conn_by_user(name)) {
272 return;
273 }
274
275 /* next try bare guest name */
276 fc_strlcpy(name, GUEST_NAME, MAX_LEN_NAME);
277 if (!conn_by_user(name)) {
278 return;
279 }
280
281 /* bare name is taken, append numbers */
282 for (i = 1; ; i++) {
283 fc_snprintf(name, MAX_LEN_NAME, "%s%u", GUEST_NAME, i);
284
285 /* attempt to find this name; if we can't we're good to go */
286 if (!conn_by_user(name)) {
287 break;
288 }
289
290 /* Prevent endless loops. */
291 fc_assert_ret(i < 2 * MAX_NUM_PLAYERS);
292 }
293}
294
295/************************************************************************/
301 static bool is_good_password(const char *password, char *msg)
302{
303 int i, num_caps = 0, num_nums = 0;
304
305 /* check password length */
306 if (strlen(password) < MIN_PASSWORD_LEN) {
307 fc_snprintf(msg, MAX_LEN_MSG,
308 _("Your password is too short, the minimum length is %d. "
309 "Try again."), MIN_PASSWORD_LEN);
310 return FALSE;
311 }
312
313 fc_snprintf(msg, MAX_LEN_MSG,
314 _("The password must have at least %d capital letters, %d "
315 "numbers, and be at minimum %d [printable] characters long. "
316 "Try again."),
317 MIN_PASSWORD_CAPS, MIN_PASSWORD_NUMS, MIN_PASSWORD_LEN);
318
319 for (i = 0; i < strlen(password); i++) {
320 if (fc_isupper(password[i])) {
321 num_caps++;
322 }
323 if (fc_isdigit(password[i])) {
324 num_nums++;
325 }
326 }
327
328 /* check number of capital letters */
329 if (num_caps < MIN_PASSWORD_CAPS) {
330 return FALSE;
331 }
332
333 /* check number of numbers */
334 if (num_nums < MIN_PASSWORD_NUMS) {
335 return FALSE;
336 }
337
338 if (!is_ascii_name(password)) {
339 return FALSE;
340 }
341
342 return TRUE;
343}
344
345/************************************************************************/
348 const char *auth_get_username(struct connection *pconn)
349{
350 fc_assert_ret_val(pconn != NULL, NULL);
351
352 return pconn->username;
353}
354
355/************************************************************************/
358 const char *auth_get_ipaddr(struct connection *pconn)
359{
360 fc_assert_ret_val(pconn != NULL, NULL);
361
362 return pconn->server.ipaddr;
363}
is_good_password
static bool is_good_password(const char *password, char *msg)
Definition auth.c:301
MIN_PASSWORD_CAPS
#define MIN_PASSWORD_CAPS
Definition auth.c:52
MIN_PASSWORD_NUMS
#define MIN_PASSWORD_NUMS
Definition auth.c:53
MIN_PASSWORD_LEN
#define MIN_PASSWORD_LEN
Definition auth.c:51
auth_handle_reply
bool auth_handle_reply(struct connection *pconn, char *password)
Definition auth.c:156
is_guest_name
static bool is_guest_name(const char *name)
Definition auth.c:257
auth_fail_wait
static const int auth_fail_wait[]
Definition auth.c:60
auth_get_username
const char * auth_get_username(struct connection *pconn)
Definition auth.c:348
auth_process_status
void auth_process_status(struct connection *pconn)
Definition auth.c:207
MAX_AUTH_TRIES
#define MAX_AUTH_TRIES
Definition auth.c:55
auth_get_ipaddr
const char * auth_get_ipaddr(struct connection *pconn)
Definition auth.c:358
GUEST_NAME
#define GUEST_NAME
Definition auth.c:49
auth_user
bool auth_user(struct connection *pconn, char *username)
Definition auth.c:73
MAX_WAIT_TIME
#define MAX_WAIT_TIME
Definition auth.c:56
get_unique_guest_name
static void get_unique_guest_name(char *name)
Definition auth.c:266
auth.h
incite_cost
char * incite_cost
Definition comments.c:74
MAX_LEN_MSG
#define MAX_LEN_MSG
Definition conn_types.h:37
AUTH_NEWUSER_RETRY
@ AUTH_NEWUSER_RETRY
Definition conn_types.h:45
AUTH_NEWUSER_FIRST
@ AUTH_NEWUSER_FIRST
Definition conn_types.h:43
AUTH_LOGIN_RETRY
@ AUTH_LOGIN_RETRY
Definition conn_types.h:44
AUTH_LOGIN_FIRST
@ AUTH_LOGIN_FIRST
Definition conn_types.h:42
reject_new_connection
void reject_new_connection(const char *msg, struct connection *pconn)
Definition connecthand.c:375
connection_close_server
void connection_close_server(struct connection *pconn, const char *reason)
Definition connecthand.c:1006
establish_new_connection
void establish_new_connection(struct connection *pconn)
Definition connecthand.c:130
connecthand.h
conn_by_user
struct connection * conn_by_user(const char *user_name)
Definition connection.c:377
connection.h
AS_REQUESTING_OLD_PASS
@ AS_REQUESTING_OLD_PASS
Definition connection.h:96
AS_FAILED
@ AS_FAILED
Definition connection.h:94
AS_NOT_ESTABLISHED
@ AS_NOT_ESTABLISHED
Definition connection.h:93
AS_REQUESTING_NEW_PASS
@ AS_REQUESTING_NEW_PASS
Definition connection.h:95
AS_ESTABLISHED
@ AS_ESTABLISHED
Definition connection.h:97
MAX_NUM_PLAYERS
#define MAX_NUM_PLAYERS
Definition fc_types.h:36
MAX_LEN_NAME
#define MAX_LEN_NAME
Definition fc_types.h:66
fcdb.h
fcintl.h
_
#define _(String)
Definition fcintl.h:67
ftc_warning
const struct ft_color ftc_warning
Definition featured_text.c:75
name
const char * name
Definition inputfile.c:127
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
log_normal
#define log_normal(message,...)
Definition log.h:107
log_error
#define log_error(message,...)
Definition log.h:103
luascript_types.h
md5.h
notify_conn
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:239
notify_conn_early
void notify_conn_early(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:264
notify.h
packets.h
dsend_packet_authentication_req
int dsend_packet_authentication_req(struct connection *pc, enum authentication_type type, const char *message)
Definition packets_gen.c:2103
send_packet_authentication_req
int send_packet_authentication_req(struct connection *pc, const struct packet_authentication_req *packet)
Definition packets_gen.c:2091
registry.h
script_fcdb_call
bool script_fcdb_call(const char *func_name,...)
Definition script_fcdb.c:359
script_fcdb.h
sernet.h
is_ascii_name
bool is_ascii_name(const char *name)
Definition shared.c:283
shared.h
srvarg
struct server_arguments srvarg
Definition srv_main.c:176
srv_main.h
connection
Definition connection.h:136
packet_authentication_req
Definition packets_gen.h:59
packet_authentication_req::type
enum authentication_type type
Definition packets_gen.h:60
server_arguments::auth_allow_guests
bool auth_allow_guests
Definition srv_main.h:58
server_arguments::auth_allow_newusers
bool auth_allow_newusers
Definition srv_main.h:59
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
fc_isdigit
bool fc_isdigit(char c)
Definition support.c:1232
fc_isupper
bool fc_isupper(char c)
Definition support.c:1265
fc_strncasecmp
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:238
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
fc_strncmp
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:154