Skip to content
This repository was archived by the owner on Aug 20, 2020. It is now read-only.

Commit 67dc261

Browse files
committed
Use mysql_base abstraction, fix crash on player name > 32 chars
1 parent d820a7a commit 67dc261

File tree

2 files changed

+132
-70
lines changed

2 files changed

+132
-70
lines changed

auth_txt_import.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function thismod.import_auth_txt()
88
local auth_file_path = minetest.get_worldpath() .. '/auth.txt'
99
local create_auth_stmt = thismod.create_auth_stmt
1010
local create_auth_params = thismod.create_auth_params
11-
local conn = thismod.conn
11+
local conn = mysql_base.conn
1212
local file, errmsg = io.open(auth_file_path, 'rb')
1313
if not file then
1414
minetest.log('action', modname .. ": " .. auth_file_path .. " could not be opened for reading" ..

init.lua

+131-69
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,35 @@ local thismod = {
66
}
77
_G[modname] = thismod
88

9+
local LogI = mysql_base.mklog('action', modname)
10+
local LogE = mysql_base.mklog('error', modname)
11+
912
if not mysql_base.enabled then
10-
minetest.log('action', modname .. ": mysql_base disabled, not loading mod")
13+
LogI("mysql_base disabled, not loading mod")
1114
return
1215
end
1316

1417
local singleplayer = minetest.is_singleplayer() -- Caching is OK since you can't open a game to
1518
-- multiplayer unless you restart it.
1619
if not minetest.setting_get(modname .. '.enable_singleplayer') and singleplayer then
17-
minetest.log('action', modname .. ": Not adding auth handler because of singleplayer game")
20+
LogI("Not adding auth handler because of singleplayer game")
1821
return
1922
end
2023

21-
enabled = true
24+
thismod.enabled = true
2225

26+
local LogV = function() end
2327
do
2428
local get = mysql_base.mkget(modname)
29+
if get('verbose') == 'true' then
30+
LogI("Verbose logging enabled")
31+
LogV = mysql_base.mklog('verbose', modname)
32+
end
2533

2634
local conn, dbname = mysql_base.conn, mysql_base.dbname
2735

2836
local tables = {}
37+
thismod.tables = tables
2938
do -- Tables and schema settings
3039
local t_auths = get('db.tables.auths')
3140
if type(t_auths) == 'table' then
@@ -72,66 +81,64 @@ do
7281
if not mysql_base.table_exists(tables.auths.name) then
7382
-- Auth table doesn't exist, create it
7483
local S = tables.auths.schema
75-
conn:query('CREATE TABLE ' .. tables.auths.name .. ' (' ..
76-
S.userid .. ' ' .. S.userid_type .. ' NOT NULL AUTO_INCREMENT,' ..
77-
S.username .. ' ' .. S.username_type .. ' NOT NULL,' ..
78-
S.password .. ' ' .. S.password_type .. ' NOT NULL,' ..
79-
S.privs .. ' ' .. S.privs_type .. ' NOT NULL,' ..
80-
S.lastlogin .. ' ' .. S.lastlogin_type .. ',' ..
81-
'PRIMARY KEY (' .. S.userid .. '),' ..
82-
'UNIQUE (' .. S.username .. ')' ..
83-
')')
84-
minetest.log('action', modname .. " created table '" .. dbname .. "." .. tables.auths.name ..
85-
"'")
84+
mysql_base.create_table(tables.auths.name, {
85+
columns = {
86+
{S.userid, S.userid_type, notnull = true, autoincrement = true},
87+
{S.username, S.username_type, notnull = true},
88+
{S.password, S.password_type, notnull = true},
89+
{S.privs, S.privs_type, notnull = true},
90+
{S.lastlogin, S.lastlogin_type},
91+
},
92+
pkey = {S.userid},
93+
unique = {S.username},
94+
})
95+
LogI("Created table '" .. dbname .. "." .. tables.auths.name .. "'")
8696
auth_table_created = true
8797
end
8898

8999
local S = tables.auths.schema
90-
local get_auth_stmt = conn:prepare('SELECT ' .. S.userid .. ',' .. S.password .. ',' .. S.privs ..
91-
',' .. S.lastlogin .. ' FROM ' .. tables.auths.name .. ' WHERE ' .. S.username .. '=?')
100+
local get_auth_stmt, get_auth_params, get_auth_results = mysql_base.prepare_select(
101+
tables.auths.name, {
102+
{S.userid, S.userid_type},
103+
{S.password, S.password_type},
104+
{S.privs, S.privs_type},
105+
{S.lastlogin, S.lastlogin_type}},
106+
S.username .. '=?', {S.username_type})
92107
thismod.get_auth_stmt = get_auth_stmt
93-
local get_auth_params = get_auth_stmt:bind_params({S.username_type})
94-
thismod.get_auth_params = get_auth_params
95-
local get_auth_results = get_auth_stmt:bind_result({S.userid_type, S.password_type, S.privs_type,
96-
S.lastlogin_type})
97-
thismod.get_auth_results = get_auth_results
98108

99-
local create_auth_stmt = conn:prepare('INSERT INTO ' .. tables.auths.name .. '(' .. S.username ..
100-
',' .. S.password .. ',' .. S.privs .. ',' .. S.lastlogin .. ') VALUES (?,?,?,?)')
109+
local create_auth_stmt, create_auth_params = mysql_base.prepare_insert(
110+
tables.auths.name, {
111+
{S.username, S.username_type},
112+
{S.password, S.password_type},
113+
{S.privs, S.privs_type},
114+
{S.lastlogin, S.lastlogin_type},
115+
})
101116
thismod.create_auth_stmt = create_auth_stmt
102-
local create_auth_params = create_auth_stmt:bind_params({S.username_type, S.password_type,
103-
S.privs_type, S.lastlogin_type})
104117
thismod.create_auth_params = create_auth_params
118+
local max_name_len = tonumber(create_auth_params.buffer[0].buffer_length)
119+
local max_pass_len = tonumber(create_auth_params.buffer[1].buffer_length)
105120

106-
local delete_auth_stmt = conn:prepare('DELETE FROM ' .. tables.auths.name .. ' WHERE ' ..
107-
S.username .. '=?')
108-
thismod.delete_auth_stmt = delete_auth_stmt
109-
local delete_auth_params = delete_auth_stmt:bind_params({S.username_type})
110-
thismod.delete_auth_params = delete_auth_params
121+
local delete_auth_stmt, delete_auth_params = mysql_base.prepare_delete(tables.auths.name,
122+
S.username .. '=?', {S.username_type})
111123

112-
local set_password_stmt = conn:prepare('UPDATE ' .. tables.auths.name .. ' SET ' .. S.password ..
113-
'=? WHERE ' .. S.username .. '=?')
114-
thismod.set_password_stmt = set_password_stmt
115-
local set_password_params = set_password_stmt:bind_params({S.password_type, S.username_type})
116-
thismod.set_password_params = set_password_params
124+
local set_password_stmt, set_password_params = mysql_base.prepare_update(tables.auths.name,
125+
{{S.password, S.password_type}},
126+
S.username .. '=?', {S.username_type})
117127

118-
local set_privileges_stmt = conn:prepare('UPDATE ' .. tables.auths.name .. ' SET ' .. S.privs ..
119-
'=? WHERE ' .. S.username .. '=?')
120-
thismod.set_privileges_stmt = set_privileges_stmt
121-
local set_privileges_params = set_privileges_stmt:bind_params({S.privs_type, S.username_type})
122-
thismod.set_privileges_params = set_privileges_params
128+
local set_privileges_stmt, set_privileges_params = mysql_base.prepare_update(tables.auths.name,
129+
{{S.privs, S.privs_type}},
130+
S.username .. '=?', {S.username_type})
131+
local max_privs_len = tonumber(set_privileges_params.buffer[0].buffer_length)
123132

124-
local record_login_stmt = conn:prepare('UPDATE ' .. tables.auths.name .. ' SET ' ..
125-
S.lastlogin .. '=? WHERE ' .. S.username .. '=?')
126-
thismod.record_login_stmt = record_login_stmt
127-
local record_login_params = record_login_stmt:bind_params({S.lastlogin_type, S.username_type})
128-
thismod.record_login_params = record_login_params
133+
local record_login_stmt, record_login_params = mysql_base.prepare_update(tables.auths.name,
134+
{{S.lastlogin, S.lastlogin_type}},
135+
S.username .. '=?', {S.username_type})
129136

130137
local enumerate_auths_query = 'SELECT ' .. S.username .. ',' .. S.password .. ',' .. S.privs ..
131138
',' .. S.lastlogin .. ' FROM ' .. tables.auths.name
132139
thismod.enumerate_auths_query = enumerate_auths_query
133140

134-
if auth_table_created and get('import_auth_txt_on_table_create') ~= 'false' then
141+
if auth_table_created and get('import_auth_txt_on_table_create') == 'true' then
135142
if not thismod.import_auth_txt then
136143
dofile(modpath .. '/auth_txt_import.lua')
137144
end
@@ -141,10 +148,14 @@ do
141148
thismod.auth_handler = {
142149
get_auth = function(name)
143150
assert(type(name) == 'string')
151+
if name:len() > max_name_len then
152+
LogE("get_auth(" .. name .. ") failed: name too long (max " .. max_name_len .. ")")
153+
return nil
154+
end
144155
get_auth_params:set(1, name)
145156
local success, msg = pcall(get_auth_stmt.exec, get_auth_stmt)
146157
if not success then
147-
minetest.log('error', modname .. ": get_auth(" .. name .. ") failed: " .. msg)
158+
LogE("get_auth(" .. name .. ") failed: " .. msg)
148159
return nil
149160
end
150161
get_auth_stmt:store_result()
@@ -153,12 +164,16 @@ do
153164
return nil
154165
end
155166
while get_auth_stmt:fetch() do
156-
minetest.log('warning', modname .. ": get_auth(" .. name .. "): multiples lines were" ..
157-
" returned")
167+
error(modname .. ": get_auth(" .. name .. "): multiples lines were returned")
158168
end
159169
local userid, password, privs_str, lastlogin = get_auth_results:get(1),
160170
get_auth_results:get(2), get_auth_results:get(3), get_auth_results:get(4)
161-
local admin = (name == minetest.setting_get("name"))
171+
local admin
172+
if minetest.settings then
173+
admin = (name == minetest.settings:get("name"))
174+
else
175+
admin = (name == minetest.setting_get("name"))
176+
end
162177
local privs
163178
if singleplayer or admin then
164179
privs = {}
@@ -175,6 +190,8 @@ do
175190
else
176191
privs = minetest.string_to_privs(privs_str)
177192
end
193+
LogV("get_auth(" .. name .. ") -> {userid:" .. userid .. ", privileges: " ..
194+
table.concat(privs, ',') .. "}")
178195
return {
179196
userid = userid,
180197
password = password,
@@ -185,56 +202,83 @@ do
185202
create_auth = function(name, password, reason)
186203
assert(type(name) == 'string')
187204
assert(type(password) == 'string')
188-
minetest.log('info', modname .. " creating player '"..name.."'" .. (reason or ""))
205+
LogV("create_auth(" .. name .. ", ###" .. (reason and (", " .. reason) or "") .. ")")
206+
LogI("Creating player '" .. name .. "'" .. (reason or ""))
207+
if name:len() > max_name_len then
208+
LogE("create_auth(" .. name .. ") failed: name too long (max " .. max_name_len .. ")")
209+
return false
210+
end
211+
if password:len() > max_pass_len then
212+
LogE("create_auth(" .. name .. ") failed: password too long (max " .. max_pass_len .. ")")
213+
return false
214+
end
189215
create_auth_params:set(1, name)
190216
create_auth_params:set(2, password)
191-
create_auth_params:set(3, minetest.setting_get("default_privs"))
217+
if minetest.settings then
218+
create_auth_params:set(3, minetest.settings:get("default_privs"))
219+
else
220+
create_auth_params:set(3, minetest.setting_get("default_privs"))
221+
end
192222
create_auth_params:set(4, math.floor(os.time()))
193223
local success, msg = pcall(create_auth_stmt.exec, create_auth_stmt)
194224
if not success then
195-
minetest.log('error', modname .. ": create_auth(" .. name .. ") failed: " .. msg)
225+
LogE("create_auth(" .. name .. ") failed: " .. msg)
196226
return false
197227
end
198228
if create_auth_stmt:affected_rows() ~= 1 then
199-
minetest.log('error', modname .. ": create_auth(" .. name .. ") failed: affected row" ..
200-
" count is " .. create_auth_stmt:affected_rows() .. ", expected 1")
229+
LogE("create_auth(" .. name .. ") failed: affected row count is " ..
230+
create_auth_stmt:affected_rows() .. ", expected 1")
201231
return false
202232
end
203233
return true
204234
end,
205235
delete_auth = function(name)
206236
assert(type(name) == 'string')
207-
minetest.log('info', modname .. " deleting player '"..name.."'")
237+
LogV("delete_auth(" .. name .. ")")
238+
LogI("Deleting player '"..name.."'")
239+
if name:len() > max_name_len then
240+
LogE("delete_auth(" .. name .. ") failed: name too long (max " .. max_name_len .. ")")
241+
return false
242+
end
208243
delete_auth_params:set(1, name)
209244
local success, msg = pcall(delete_auth_stmt.exec, delete_auth_stmt)
210245
if not success then
211-
minetest.log('error', modname .. ": delete_auth(" .. name .. ") failed: " .. msg)
246+
LogE("delete_auth(" .. name .. ") failed: " .. msg)
212247
return false
213248
end
214249
if delete_auth_stmt:affected_rows() ~= 1 then
215-
minetest.log('error', modname .. ": delete_auth(" .. name .. ") failed: affected row" ..
216-
" count is " .. delete_auth_stmt:affected_rows() .. ", expected 1")
250+
LogE("delete_auth(" .. name .. ") failed: affected row count is " ..
251+
delete_auth_stmt:affected_rows() .. ", expected 1")
217252
return false
218253
end
219254
return true
220255
end,
221256
set_password = function(name, password)
222257
assert(type(name) == 'string')
223258
assert(type(password) == 'string')
259+
LogV("set_password(" .. name .. ", ###)")
260+
if name:len() > max_name_len then
261+
LogE("create_auth(" .. name .. ") failed: name too long (max " .. max_name_len .. ")")
262+
return false
263+
end
264+
if password:len() > max_pass_len then
265+
LogE("create_auth(" .. name .. ") failed: password too long (max " .. max_pass_len .. ")")
266+
return false
267+
end
224268
if not thismod.auth_handler.get_auth(name) then
225269
return thismod.auth_handler.create_auth(name, password, " because set_password was requested")
226270
else
227-
minetest.log('info', modname .. " setting password of player '" .. name .. "'")
271+
LogI("Setting password of player '" .. name .. "'")
228272
set_password_params:set(1, password)
229273
set_password_params:set(2, name)
230274
local success, msg = pcall(set_password_stmt.exec, set_password_stmt)
231275
if not success then
232-
minetest.log('error', modname .. ": set_password(" .. name .. ") failed: " .. msg)
276+
LogE("set_password(" .. name .. ") failed: " .. msg)
233277
return false
234278
end
235279
if set_password_stmt:affected_rows() ~= 1 then
236-
minetest.log('error', modname .. ": set_password(" .. name .. ") failed: affected row" ..
237-
" count is " .. set_password_stmt:affected_rows() .. ", expected 1")
280+
LogE("set_password(" .. name .. ") failed: affected row count is " ..
281+
set_password_stmt:affected_rows() .. ", expected 1")
238282
return false
239283
end
240284
return true
@@ -243,11 +287,23 @@ do
243287
set_privileges = function(name, privileges)
244288
assert(type(name) == 'string')
245289
assert(type(privileges) == 'table')
246-
set_privileges_params:set(1, minetest.privs_to_string(privileges))
290+
local privstr = minetest.privs_to_string(privileges)
291+
LogV("set_privileges(" .. name .. ", {" .. table.concat(privileges, ', ') .. "}) [" ..
292+
privstr .. "]")
293+
if name:len() > max_name_len then
294+
LogE("set_privileges(" .. name .. ") failed: name too long (max " .. max_name_len .. ")")
295+
return false
296+
end
297+
if privstr:len() > max_privs_len then
298+
LogE("create_auth(" .. name .. ") failed: priv string too long (max " ..
299+
max_privs_len .. ")")
300+
return false
301+
end
302+
set_privileges_params:set(1, privstr)
247303
set_privileges_params:set(2, name)
248304
local success, msg = pcall(set_privileges_stmt.exec, set_privileges_stmt)
249305
if not success then
250-
minetest.log('error', modname .. ": set_privileges(" .. name .. ") failed: " .. msg)
306+
LogE("set_privileges(" .. name .. ") failed: " .. msg)
251307
return false
252308
end
253309
minetest.notify_authentication_modified(name)
@@ -258,21 +314,27 @@ do
258314
end,
259315
record_login = function(name)
260316
assert(type(name) == 'string')
317+
LogV("record_login(" .. name .. ")")
318+
if name:len() > max_name_len then
319+
LogE("set_privileges(" .. name .. ") failed: name too long (max " .. max_name_len .. ")")
320+
return false
321+
end
261322
record_login_params:set(1, math.floor(os.time()))
262323
record_login_params:set(2, name)
263324
local success, msg = pcall(record_login_stmt.exec, record_login_stmt)
264325
if not success then
265-
minetest.log('error', modname .. ": record_login(" .. name .. ") failed: " .. msg)
326+
LogE("record_login(" .. name .. ") failed: " .. msg)
266327
return false
267328
end
268329
if record_login_stmt:affected_rows() ~= 1 then
269-
minetest.log('error', modname .. ": record_login(" .. name .. ") failed: affected row" ..
270-
" count is " .. record_login_stmt:affected_rows() .. ", expected 1")
330+
LogE("record_login(" .. name .. ") failed: affected row count is " ..
331+
record_login_stmt:affected_rows() .. ", expected 1")
271332
return false
272333
end
273334
return true
274335
end,
275336
enumerate_auths = function()
337+
LogV("enumerate_auths()")
276338
conn:query(enumerate_auths_query)
277339
local res = conn:store_result()
278340
return function()
@@ -292,7 +354,7 @@ do
292354
end
293355

294356
minetest.register_authentication_handler(thismod.auth_handler)
295-
minetest.log('action', modname .. ": Registered auth handler")
357+
LogI("Registered auth handler")
296358

297359
mysql_base.register_on_shutdown(function()
298360
thismod.get_auth_stmt:free_result()

0 commit comments

Comments
 (0)