Freeciv-3.3
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 */
60static 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/************************************************************************/
73bool 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)) {
80
81 sz_strlcpy(tmpname, username);
82 get_unique_guest_name(username);
83
84 if (fc_strncmp(tmpname, username, MAX_LEN_NAME)) {
86 _("Warning: the guest name '%s' has been "
87 "taken, renaming to user '%s'."), tmpname, username);
88 }
89 sz_strlcpy(pconn->username, username);
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)) {
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");
113 _("There was an error reading the user "
114 "database, logging in as guest connection '%s'."),
115 pconn->username);
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);
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 */
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."));
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/************************************************************************/
156bool 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 {
172 return TRUE;
173 }
174 }
175
176 if (!script_fcdb_call("user_save", pconn, password)) {
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
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) {
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/************************************************************************/
208{
209 switch (pconn->server.status) {
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 {
227
228 pconn->server.status = AS_REQUESTING_OLD_PASS;
230 sz_strlcpy(request.message,
231 _("Your password is incorrect. Try again."));
233 }
234 }
235 break;
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/************************************************************************/
257static bool is_guest_name(const char *name)
258{
260}
261
262/************************************************************************/
266static void get_unique_guest_name(char *name)
267{
268 unsigned int i;
269
270 /* first see if the given name is suitable */
272 return;
273 }
274
275 /* next try bare guest name */
277 if (!conn_by_user(name)) {
278 return;
279 }
280
281 /* bare name is taken, append numbers */
282 for (i = 1; ; 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. */
292 }
293}
294
295/************************************************************************/
301static 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) {
308 _("Your password is too short, the minimum length is %d. "
309 "Try again."), MIN_PASSWORD_LEN);
310 return FALSE;
311 }
312
314 _("The password must have at least %d capital letters, %d "
315 "numbers, and be at minimum %d [printable] characters long. "
316 "Try again."),
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 */
330 return FALSE;
331 }
332
333 /* check number of numbers */
335 return FALSE;
336 }
337
338 if (!is_ascii_name(password)) {
339 return FALSE;
340 }
341
342 return TRUE;
343}
344
345/************************************************************************/
349{
351
352 return pconn->username;
353}
354
355/************************************************************************/
358const char *auth_get_ipaddr(struct connection *pconn)
359{
361
362 return pconn->server.ipaddr;
363}
static bool is_good_password(const char *password, char *msg)
Definition auth.c:301
#define MIN_PASSWORD_CAPS
Definition auth.c:52
#define MIN_PASSWORD_NUMS
Definition auth.c:53
#define MIN_PASSWORD_LEN
Definition auth.c:51
bool auth_handle_reply(struct connection *pconn, char *password)
Definition auth.c:156
static bool is_guest_name(const char *name)
Definition auth.c:257
static const int auth_fail_wait[]
Definition auth.c:60
const char * auth_get_username(struct connection *pconn)
Definition auth.c:348
void auth_process_status(struct connection *pconn)
Definition auth.c:207
#define MAX_AUTH_TRIES
Definition auth.c:55
const char * auth_get_ipaddr(struct connection *pconn)
Definition auth.c:358
#define GUEST_NAME
Definition auth.c:49
bool auth_user(struct connection *pconn, char *username)
Definition auth.c:73
#define MAX_WAIT_TIME
Definition auth.c:56
static void get_unique_guest_name(char *name)
Definition auth.c:266
char * incite_cost
Definition comments.c:76
#define MAX_LEN_MSG
Definition conn_types.h:37
@ AUTH_NEWUSER_RETRY
Definition conn_types.h:45
@ AUTH_NEWUSER_FIRST
Definition conn_types.h:43
@ AUTH_LOGIN_RETRY
Definition conn_types.h:44
@ AUTH_LOGIN_FIRST
Definition conn_types.h:42
void reject_new_connection(const char *msg, struct connection *pconn)
void connection_close_server(struct connection *pconn, const char *reason)
void establish_new_connection(struct connection *pconn)
struct connection * conn_by_user(const char *user_name)
Definition connection.c:377
@ AS_REQUESTING_OLD_PASS
Definition connection.h:96
@ AS_FAILED
Definition connection.h:94
@ AS_NOT_ESTABLISHED
Definition connection.h:93
@ AS_REQUESTING_NEW_PASS
Definition connection.h:95
@ AS_ESTABLISHED
Definition connection.h:97
#define MAX_NUM_PLAYERS
Definition fc_types.h:36
#define MAX_LEN_NAME
Definition fc_types.h:66
#define _(String)
Definition fcintl.h:67
const struct ft_color ftc_warning
const char * name
Definition inputfile.c:127
#define fc_assert_ret(condition)
Definition log.h:192
#define log_verbose(message,...)
Definition log.h:110
#define fc_assert(condition)
Definition log.h:177
#define fc_assert_ret_val(condition, val)
Definition log.h:195
#define log_normal(message,...)
Definition log.h:108
#define log_error(message,...)
Definition log.h:104
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:238
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:263
int dsend_packet_authentication_req(struct connection *pc, enum authentication_type type, const char *message)
int send_packet_authentication_req(struct connection *pc, const struct packet_authentication_req *packet)
bool script_fcdb_call(const char *func_name,...)
bool is_ascii_name(const char *name)
Definition shared.c:286
struct server_arguments srvarg
Definition srv_main.c:181
enum authentication_type type
Definition packets_gen.h:62
bool auth_allow_guests
Definition srv_main.h:58
bool auth_allow_newusers
Definition srv_main.h:59
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
bool fc_isdigit(char c)
Definition support.c:1218
bool fc_isupper(char c)
Definition support.c:1251
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:235
#define sz_strlcpy(dest, src)
Definition support.h:195
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:160