You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
7.4 KiB

  1. // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
  2. //
  3. // Use of this source code is governed by an MIT-style
  4. // license that can be found in the LICENSE file.
  5. // +build sqlite_userauth
  6. package sqlite3
  7. /*
  8. #cgo CFLAGS: -DSQLITE_USER_AUTHENTICATION
  9. #cgo LDFLAGS: -lm
  10. #ifndef USE_LIBSQLITE3
  11. #include <sqlite3-binding.h>
  12. #else
  13. #include <sqlite3.h>
  14. #endif
  15. #include <stdlib.h>
  16. static int
  17. _sqlite3_user_authenticate(sqlite3* db, const char* zUsername, const char* aPW, int nPW)
  18. {
  19. return sqlite3_user_authenticate(db, zUsername, aPW, nPW);
  20. }
  21. static int
  22. _sqlite3_user_add(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin)
  23. {
  24. return sqlite3_user_add(db, zUsername, aPW, nPW, isAdmin);
  25. }
  26. static int
  27. _sqlite3_user_change(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin)
  28. {
  29. return sqlite3_user_change(db, zUsername, aPW, nPW, isAdmin);
  30. }
  31. static int
  32. _sqlite3_user_delete(sqlite3* db, const char* zUsername)
  33. {
  34. return sqlite3_user_delete(db, zUsername);
  35. }
  36. static int
  37. _sqlite3_auth_enabled(sqlite3* db)
  38. {
  39. int exists = -1;
  40. sqlite3_stmt *stmt;
  41. sqlite3_prepare_v2(db, "select count(type) from sqlite_master WHERE type='table' and name='sqlite_user';", -1, &stmt, NULL);
  42. while ( sqlite3_step(stmt) == SQLITE_ROW) {
  43. exists = sqlite3_column_int(stmt, 0);
  44. }
  45. sqlite3_finalize(stmt);
  46. return exists;
  47. }
  48. */
  49. import "C"
  50. import (
  51. "errors"
  52. "unsafe"
  53. )
  54. const (
  55. SQLITE_AUTH = C.SQLITE_AUTH
  56. )
  57. var (
  58. ErrUnauthorized = errors.New("SQLITE_AUTH: Unauthorized")
  59. ErrAdminRequired = errors.New("SQLITE_AUTH: Unauthorized; Admin Privileges Required")
  60. )
  61. // Authenticate will perform an authentication of the provided username
  62. // and password against the database.
  63. //
  64. // If a database contains the SQLITE_USER table, then the
  65. // call to Authenticate must be invoked with an
  66. // appropriate username and password prior to enable read and write
  67. //access to the database.
  68. //
  69. // Return SQLITE_OK on success or SQLITE_ERROR if the username/password
  70. // combination is incorrect or unknown.
  71. //
  72. // If the SQLITE_USER table is not present in the database file, then
  73. // this interface is a harmless no-op returnning SQLITE_OK.
  74. func (c *SQLiteConn) Authenticate(username, password string) error {
  75. rv := c.authenticate(username, password)
  76. switch rv {
  77. case C.SQLITE_ERROR, C.SQLITE_AUTH:
  78. return ErrUnauthorized
  79. case C.SQLITE_OK:
  80. return nil
  81. default:
  82. return c.lastError()
  83. }
  84. }
  85. // authenticate provides the actual authentication to SQLite.
  86. // This is not exported for usage in Go.
  87. // It is however exported for usage within SQL by the user.
  88. //
  89. // Returns:
  90. // C.SQLITE_OK (0)
  91. // C.SQLITE_ERROR (1)
  92. // C.SQLITE_AUTH (23)
  93. func (c *SQLiteConn) authenticate(username, password string) int {
  94. // Allocate C Variables
  95. cuser := C.CString(username)
  96. cpass := C.CString(password)
  97. // Free C Variables
  98. defer func() {
  99. C.free(unsafe.Pointer(cuser))
  100. C.free(unsafe.Pointer(cpass))
  101. }()
  102. return int(C._sqlite3_user_authenticate(c.db, cuser, cpass, C.int(len(password))))
  103. }
  104. // AuthUserAdd can be used (by an admin user only)
  105. // to create a new user. When called on a no-authentication-required
  106. // database, this routine converts the database into an authentication-
  107. // required database, automatically makes the added user an
  108. // administrator, and logs in the current connection as that user.
  109. // The AuthUserAdd only works for the "main" database, not
  110. // for any ATTACH-ed databases. Any call to AuthUserAdd by a
  111. // non-admin user results in an error.
  112. func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
  113. isAdmin := 0
  114. if admin {
  115. isAdmin = 1
  116. }
  117. rv := c.authUserAdd(username, password, isAdmin)
  118. switch rv {
  119. case C.SQLITE_ERROR, C.SQLITE_AUTH:
  120. return ErrAdminRequired
  121. case C.SQLITE_OK:
  122. return nil
  123. default:
  124. return c.lastError()
  125. }
  126. }
  127. // authUserAdd enables the User Authentication if not enabled.
  128. // Otherwise it will add a user.
  129. //
  130. // When user authentication is already enabled then this function
  131. // can only be called by an admin.
  132. //
  133. // This is not exported for usage in Go.
  134. // It is however exported for usage within SQL by the user.
  135. //
  136. // Returns:
  137. // C.SQLITE_OK (0)
  138. // C.SQLITE_ERROR (1)
  139. // C.SQLITE_AUTH (23)
  140. func (c *SQLiteConn) authUserAdd(username, password string, admin int) int {
  141. // Allocate C Variables
  142. cuser := C.CString(username)
  143. cpass := C.CString(password)
  144. // Free C Variables
  145. defer func() {
  146. C.free(unsafe.Pointer(cuser))
  147. C.free(unsafe.Pointer(cpass))
  148. }()
  149. return int(C._sqlite3_user_add(c.db, cuser, cpass, C.int(len(password)), C.int(admin)))
  150. }
  151. // AuthUserChange can be used to change a users
  152. // login credentials or admin privilege. Any user can change their own
  153. // login credentials. Only an admin user can change another users login
  154. // credentials or admin privilege setting. No user may change their own
  155. // admin privilege setting.
  156. func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error {
  157. isAdmin := 0
  158. if admin {
  159. isAdmin = 1
  160. }
  161. rv := c.authUserChange(username, password, isAdmin)
  162. switch rv {
  163. case C.SQLITE_ERROR, C.SQLITE_AUTH:
  164. return ErrAdminRequired
  165. case C.SQLITE_OK:
  166. return nil
  167. default:
  168. return c.lastError()
  169. }
  170. }
  171. // authUserChange allows to modify a user.
  172. // Users can change their own password.
  173. //
  174. // Only admins can change passwords for other users
  175. // and modify the admin flag.
  176. //
  177. // The admin flag of the current logged in user cannot be changed.
  178. // THis ensures that their is always an admin.
  179. //
  180. // This is not exported for usage in Go.
  181. // It is however exported for usage within SQL by the user.
  182. //
  183. // Returns:
  184. // C.SQLITE_OK (0)
  185. // C.SQLITE_ERROR (1)
  186. // C.SQLITE_AUTH (23)
  187. func (c *SQLiteConn) authUserChange(username, password string, admin int) int {
  188. // Allocate C Variables
  189. cuser := C.CString(username)
  190. cpass := C.CString(password)
  191. // Free C Variables
  192. defer func() {
  193. C.free(unsafe.Pointer(cuser))
  194. C.free(unsafe.Pointer(cpass))
  195. }()
  196. return int(C._sqlite3_user_change(c.db, cuser, cpass, C.int(len(password)), C.int(admin)))
  197. }
  198. // AuthUserDelete can be used (by an admin user only)
  199. // to delete a user. The currently logged-in user cannot be deleted,
  200. // which guarantees that there is always an admin user and hence that
  201. // the database cannot be converted into a no-authentication-required
  202. // database.
  203. func (c *SQLiteConn) AuthUserDelete(username string) error {
  204. rv := c.authUserDelete(username)
  205. switch rv {
  206. case C.SQLITE_ERROR, C.SQLITE_AUTH:
  207. return ErrAdminRequired
  208. case C.SQLITE_OK:
  209. return nil
  210. default:
  211. return c.lastError()
  212. }
  213. }
  214. // authUserDelete can be used to delete a user.
  215. //
  216. // This function can only be executed by an admin.
  217. //
  218. // This is not exported for usage in Go.
  219. // It is however exported for usage within SQL by the user.
  220. //
  221. // Returns:
  222. // C.SQLITE_OK (0)
  223. // C.SQLITE_ERROR (1)
  224. // C.SQLITE_AUTH (23)
  225. func (c *SQLiteConn) authUserDelete(username string) int {
  226. // Allocate C Variables
  227. cuser := C.CString(username)
  228. // Free C Variables
  229. defer func() {
  230. C.free(unsafe.Pointer(cuser))
  231. }()
  232. return int(C._sqlite3_user_delete(c.db, cuser))
  233. }
  234. // AuthEnabled checks if the database is protected by user authentication
  235. func (c *SQLiteConn) AuthEnabled() (exists bool) {
  236. rv := c.authEnabled()
  237. if rv == 1 {
  238. exists = true
  239. }
  240. return
  241. }
  242. // authEnabled perform the actual check for user authentication.
  243. //
  244. // This is not exported for usage in Go.
  245. // It is however exported for usage within SQL by the user.
  246. //
  247. // Returns:
  248. // 0 - Disabled
  249. // 1 - Enabled
  250. func (c *SQLiteConn) authEnabled() int {
  251. return int(C._sqlite3_auth_enabled(c.db))
  252. }
  253. // EOF