PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/nxmydb/branches/1.x/source/user.c

http://nxscripts.googlecode.com/
C | 545 lines | 355 code | 114 blank | 76 comment | 99 complexity | 75fbb6f59fd7f6d0b9a28e74a427ab31 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause
  1. /*
  2. nxMyDB - MySQL Database for ioFTPD
  3. Copyright (c) 2006-2009 neoxed
  4. Module Name:
  5. User Module
  6. Author:
  7. neoxed (neoxed@gmail.com) Jun 3, 2006
  8. Abstract:
  9. Entry point and functions for the user module.
  10. */
  11. #include <base.h>
  12. #include <backends.h>
  13. #include <database.h>
  14. static INT UserFinalize(VOID);
  15. static INT32 UserCreate(CHAR *userName);
  16. static INT UserRename(CHAR *userName, INT32 userId, CHAR *newName);
  17. static INT UserDelete(CHAR *userName, INT32 userId);
  18. static INT UserLock(USERFILE *userFile);
  19. static INT UserUnlock(USERFILE *userFile);
  20. static INT UserOpen(CHAR *userName, USERFILE *userFile);
  21. static INT UserWrite(USERFILE *userFile);
  22. static INT UserClose(USERFILE *userFile);
  23. static USER_MODULE *userModule = NULL;
  24. INT UserModuleInit(USER_MODULE *module)
  25. {
  26. ASSERT(module != NULL);
  27. TRACE("module=%p", module);
  28. // Initialize module
  29. module->tszModuleName = MODULE_NAME;
  30. module->DeInitialize = UserFinalize;
  31. module->Create = UserCreate;
  32. module->Rename = UserRename;
  33. module->Delete = UserDelete;
  34. module->Lock = UserLock;
  35. module->Unlock = UserUnlock;
  36. module->Open = UserOpen;
  37. module->Write = UserWrite;
  38. module->Close = UserClose;
  39. // Initialize database
  40. if (!DbInit(module->GetProc)) {
  41. TRACE("Unable to initialize module.");
  42. return UM_ERROR;
  43. }
  44. userModule = module;
  45. return UM_SUCCESS;
  46. }
  47. static INT UserFinalize(VOID)
  48. {
  49. // Finalize database
  50. DbFinalize();
  51. userModule = NULL;
  52. return UM_SUCCESS;
  53. }
  54. static INT32 UserCreate(CHAR *userName)
  55. {
  56. DB_CONTEXT *db;
  57. MOD_CONTEXT *mod;
  58. DWORD result;
  59. INT32 userId = -1;
  60. USERFILE userFile;
  61. TRACE("userName=%s", userName);
  62. if (!DbAcquire(&db)) {
  63. return userId;
  64. }
  65. // Module context is required for all file operations
  66. mod = MemAllocate(sizeof(MOD_CONTEXT));
  67. if (mod == NULL) {
  68. result = ERROR_NOT_ENOUGH_MEMORY;
  69. LOG_ERROR("Unable to allocate memory for module context.");
  70. } else {
  71. // Initialize MOD_CONTEXT structure
  72. mod->file = INVALID_HANDLE_VALUE;
  73. // Initialize USERFILE structure
  74. ZeroMemory(&userFile, sizeof(USERFILE));
  75. userFile.Groups[0] = NOGROUP_ID;
  76. userFile.Groups[1] = -1;
  77. userFile.AdminGroups[0] = -1;
  78. userFile.lpInternal = mod;
  79. // Read "Default.User" file
  80. result = FileUserDefault(&userFile);
  81. if (result != ERROR_SUCCESS) {
  82. LOG_WARN("Unable to read \"Default.User\" file (error %lu).", result);
  83. }
  84. // Register user
  85. result = UserRegister(userName, &userFile, &userId);
  86. if (result != ERROR_SUCCESS) {
  87. TRACE("Unable to register user (error %lu).", result);
  88. } else {
  89. // Create user file
  90. result = FileUserCreate(userId, &userFile);
  91. if (result != ERROR_SUCCESS) {
  92. LOG_WARN("Unable to create user file (error %lu).", result);
  93. } else {
  94. // Create database record
  95. result = DbUserCreate(db, userName, &userFile);
  96. if (result != ERROR_SUCCESS) {
  97. LOG_WARN("Unable to create database record (error %lu).", result);
  98. }
  99. }
  100. // If the file or database creation failed, clean-up the user file
  101. if (result != ERROR_SUCCESS) {
  102. FileUserDelete(userId);
  103. FileUserClose(&userFile);
  104. UserUnregister(userName);
  105. }
  106. }
  107. if (result != ERROR_SUCCESS) {
  108. // Free module context after all file operations
  109. MemFree(mod);
  110. // Indicate an error occured by returning an invalid user ID
  111. userId = -1;
  112. }
  113. }
  114. DbRelease(db);
  115. SetLastError(result);
  116. return userId;
  117. }
  118. static INT UserRename(CHAR *userName, INT32 userId, CHAR *newName)
  119. {
  120. DB_CONTEXT *db;
  121. DWORD result;
  122. UNREFERENCED_PARAMETER(userId);
  123. TRACE("userName=%s userId=%d newName=%s", userName, userId, newName);
  124. if (!DbAcquire(&db)) {
  125. return UM_ERROR;
  126. }
  127. // Rename database record
  128. result = DbUserRename(db, userName, newName);
  129. if (result != ERROR_SUCCESS) {
  130. LOG_ERROR("Unable to rename user database record from \"%s\" to \"%s\" (error %lu).",
  131. userName, newName, result);
  132. } else {
  133. // Register user under the new name
  134. result = UserRegisterAs(userName, newName);
  135. }
  136. DbRelease(db);
  137. SetLastError(result);
  138. return (result == ERROR_SUCCESS) ? UM_SUCCESS : UM_ERROR;
  139. }
  140. static INT UserDelete(CHAR *userName, INT32 userId)
  141. {
  142. DB_CONTEXT *db;
  143. DWORD result;
  144. TRACE("userName=%s userId=%d", userName, userId);
  145. if (!DbAcquire(&db)) {
  146. return UM_ERROR;
  147. }
  148. // Delete user file (success does not matter)
  149. result = FileUserDelete(userId);
  150. if (result != ERROR_SUCCESS) {
  151. LOG_ERROR("Unable to delete user file for \"%s\" (error %lu).", userName, result);
  152. }
  153. // Delete database record
  154. result = DbUserDelete(db, userName);
  155. if (result != ERROR_SUCCESS) {
  156. LOG_ERROR("Unable to delete user database record for \"%s\" (error %lu).", userName, result);
  157. } else {
  158. // Unregister user
  159. result = UserUnregister(userName);
  160. }
  161. DbRelease(db);
  162. SetLastError(result);
  163. return (result == ERROR_SUCCESS) ? UM_SUCCESS : UM_ERROR;
  164. }
  165. static INT UserLock(USERFILE *userFile)
  166. {
  167. CHAR *userName;
  168. DB_CONTEXT *db;
  169. DWORD result;
  170. TRACE("userFile=%p", userFile);
  171. if (!DbAcquire(&db)) {
  172. return UM_ERROR;
  173. }
  174. // Resolve user ID to user name
  175. userName = Io_Uid2User(userFile->Uid);
  176. if (userName == NULL) {
  177. result = ERROR_ID_NOT_FOUND;
  178. } else {
  179. // Lock user
  180. result = DbUserLock(db, userName, userFile);
  181. if (result != ERROR_SUCCESS) {
  182. LOG_ERROR("Unable to lock user \"%s\" (error %lu).", userName, result);
  183. }
  184. }
  185. DbRelease(db);
  186. SetLastError(result);
  187. return (result == ERROR_SUCCESS) ? UM_SUCCESS : UM_ERROR;
  188. }
  189. static INT UserUnlock(USERFILE *userFile)
  190. {
  191. CHAR *userName;
  192. DB_CONTEXT *db;
  193. DWORD result;
  194. TRACE("userFile=%p", userFile);
  195. if (!DbAcquire(&db)) {
  196. return UM_ERROR;
  197. }
  198. // Resolve user ID to user name
  199. userName = Io_Uid2User(userFile->Uid);
  200. if (userName == NULL) {
  201. result = ERROR_ID_NOT_FOUND;
  202. } else {
  203. // Unlock user
  204. result = DbUserUnlock(db, userName);
  205. if (result != ERROR_SUCCESS) {
  206. LOG_ERROR("Unable to unlock user \"%s\" (error %lu).", userName, result);
  207. }
  208. }
  209. DbRelease(db);
  210. SetLastError(result);
  211. return (result == ERROR_SUCCESS) ? UM_SUCCESS : UM_ERROR;
  212. }
  213. static INT UserOpen(CHAR *userName, USERFILE *userFile)
  214. {
  215. DB_CONTEXT *db;
  216. DWORD result;
  217. MOD_CONTEXT *mod;
  218. TRACE("userName=%s userFile=%p", userName, userFile);
  219. if (!DbAcquire(&db)) {
  220. // Return UM_DELETED instead of UM_ERROR to work around a bug in ioFTPD.
  221. return UM_DELETED;
  222. }
  223. // Module context is required for all file operations
  224. mod = MemAllocate(sizeof(MOD_CONTEXT));
  225. if (mod == NULL) {
  226. result = ERROR_NOT_ENOUGH_MEMORY;
  227. LOG_ERROR("Unable to allocate memory for module context.");
  228. } else {
  229. // Initialize MOD_CONTEXT structure
  230. mod->file = INVALID_HANDLE_VALUE;
  231. userFile->lpInternal = mod;
  232. // Open user file
  233. result = FileUserOpen(userFile->Uid, userFile);
  234. if (result != ERROR_SUCCESS) {
  235. LOG_WARN("Unable to open user file for \"%s\" (error %lu).", userName, result);
  236. } else {
  237. // Read database record
  238. result = DbUserOpen(db, userName, userFile);
  239. if (result != ERROR_SUCCESS) {
  240. LOG_WARN("Unable to open user database record for \"%s\" (error %lu).", userName, result);
  241. // Clean-up user file
  242. FileUserClose(userFile);
  243. }
  244. }
  245. // Free module context if the file/database open failed
  246. if (result != ERROR_SUCCESS) {
  247. MemFree(mod);
  248. }
  249. }
  250. DbRelease(db);
  251. //
  252. // Return UM_DELETED instead of UM_ERROR to work around a bug in ioFTPD. If
  253. // UM_ERROR is returned, ioFTPD frees part of the USERFILE structure and
  254. // may crash later on (e.g. if someone issues "SITE USERS").
  255. //
  256. SetLastError(result);
  257. return (result == ERROR_SUCCESS) ? UM_SUCCESS : UM_DELETED;
  258. }
  259. static INT UserWrite(USERFILE *userFile)
  260. {
  261. CHAR *userName;
  262. DB_CONTEXT *db;
  263. DWORD result;
  264. TRACE("userFile=%p", userFile);
  265. if (!DbAcquire(&db)) {
  266. return UM_ERROR;
  267. }
  268. // Resolve user ID to user name
  269. userName = Io_Uid2User(userFile->Uid);
  270. if (userName == NULL) {
  271. result = ERROR_ID_NOT_FOUND;
  272. } else {
  273. // Update user file (success does not matter)
  274. result = FileUserWrite(userFile);
  275. if (result != ERROR_SUCCESS) {
  276. LOG_WARN("Unable to write user file for \"%s\" (error %lu).", userName, result);
  277. }
  278. // Update user database record
  279. result = DbUserWrite(db, userName, userFile);
  280. if (result != ERROR_SUCCESS) {
  281. LOG_WARN("Unable to write user database record for \"%s\" (error %lu).", userName, result);
  282. }
  283. }
  284. DbRelease(db);
  285. SetLastError(result);
  286. return (result == ERROR_SUCCESS) ? UM_SUCCESS : UM_ERROR;
  287. }
  288. static INT UserClose(USERFILE *userFile)
  289. {
  290. DWORD result;
  291. MOD_CONTEXT *mod;
  292. TRACE("userFile=%p", userFile);
  293. mod = userFile->lpInternal;
  294. if (mod != NULL) {
  295. // Close user file (success does not matter)
  296. result = FileUserClose(userFile);
  297. if (result != ERROR_SUCCESS) {
  298. LOG_WARN("Unable to close user file (error %lu).", result);
  299. }
  300. // Close user database record (success does not matter)
  301. result = DbUserClose(userFile);
  302. if (result != ERROR_SUCCESS) {
  303. LOG_WARN("Unable to close user database record (error %lu).", result);
  304. }
  305. // Free module context
  306. MemFree(mod);
  307. userFile->lpInternal = NULL;
  308. }
  309. return UM_SUCCESS;
  310. }
  311. BOOL UserExists(CHAR *userName)
  312. {
  313. INT32 userId;
  314. ASSERT(userName != NULL);
  315. TRACE("userName=%s", userName);
  316. userId = Io_User2Uid(userName);
  317. return (userId != -1);
  318. }
  319. DWORD UserRegister(CHAR *userName, USERFILE *userFile, INT32 *userIdPtr)
  320. {
  321. DWORD errorCode = ERROR_SUCCESS;
  322. INT32 userId;
  323. ASSERT(userName != NULL);
  324. ASSERT(userFile != NULL);
  325. ASSERT(userIdPtr != NULL);
  326. TRACE("userName=%s userFile=%p userIdPtr=%p", userName, userFile, userIdPtr);
  327. userId = userModule->Register(userModule, userName, userFile);
  328. //
  329. // The "Register" function returns -1 on failure.
  330. //
  331. if (userId == -1) {
  332. errorCode = GetLastError();
  333. ASSERT(errorCode != ERROR_SUCCESS);
  334. TRACE("Unable to register user \"%s\" (error %lu).", userName, errorCode);
  335. }
  336. *userIdPtr = userId;
  337. return errorCode;
  338. }
  339. DWORD UserRegisterAs(CHAR *userName, CHAR *newName)
  340. {
  341. BOOL result;
  342. DWORD errorCode = ERROR_SUCCESS;
  343. ASSERT(userName != NULL);
  344. ASSERT(newName != NULL);
  345. TRACE("userName=%s newName=%s", userName, newName);
  346. result = userModule->RegisterAs(userModule, userName, newName);
  347. //
  348. // Unlike most boolean functions, the "RegisterAs"
  349. // function returns a non-zero value on failure.
  350. //
  351. if (result) {
  352. errorCode = GetLastError();
  353. ASSERT(errorCode != ERROR_SUCCESS);
  354. TRACE("Unable to re-register user \"%s\" as \"%s\" (error %lu).",
  355. userName, newName, errorCode);
  356. }
  357. return errorCode;
  358. }
  359. DWORD UserUnregister(CHAR *userName)
  360. {
  361. BOOL result;
  362. DWORD errorCode = ERROR_SUCCESS;
  363. ASSERT(userName != NULL);
  364. TRACE("userName=%s", userName);
  365. result = userModule->Unregister(userModule, userName);
  366. //
  367. // Unlike most boolean functions, the "Unregister"
  368. // function returns a non-zero value on failure.
  369. //
  370. if (result) {
  371. errorCode = GetLastError();
  372. ASSERT(errorCode != ERROR_SUCCESS);
  373. TRACE("Unable to unregister user \"%s\" (error %lu).", userName, errorCode);
  374. }
  375. return errorCode;
  376. }
  377. DWORD UserUpdate(USERFILE *userFile)
  378. {
  379. BOOL result;
  380. DWORD errorCode = ERROR_SUCCESS;
  381. ASSERT(userFile != NULL);
  382. TRACE("userFile=%p", userFile);
  383. result = userModule->Update(userFile);
  384. //
  385. // Unlike most boolean functions, the "Update"
  386. // function returns a non-zero value on failure.
  387. //
  388. if (result) {
  389. errorCode = GetLastError();
  390. ASSERT(errorCode != ERROR_SUCCESS);
  391. TRACE("Unable to update user ID %d (error %lu).", userFile->Uid, errorCode);
  392. }
  393. return errorCode;
  394. }
  395. DWORD UserUpdateByName(CHAR *userName, USERFILE *userFile)
  396. {
  397. BOOL result;
  398. DWORD errorCode = ERROR_SUCCESS;
  399. INT32 userId;
  400. ASSERT(userName != NULL);
  401. ASSERT(userFile != NULL);
  402. TRACE("userName=%s userFile=%p", userName, userFile);
  403. // Resolve the user name to its ID.
  404. userId = Io_User2Uid(userName);
  405. if (userId == -1) {
  406. errorCode = GetLastError();
  407. ASSERT(errorCode != ERROR_SUCCESS);
  408. TRACE("Unable to resolve user \"%s\" (error %lu).", userName, errorCode);
  409. } else {
  410. // Update the ID member before calling the "Update" function.
  411. userFile->Uid = userId;
  412. result = userModule->Update(userFile);
  413. //
  414. // Unlike most boolean functions, the "Update"
  415. // function returns a non-zero value on failure.
  416. //
  417. if (result) {
  418. errorCode = GetLastError();
  419. ASSERT(errorCode != ERROR_SUCCESS);
  420. TRACE("Unable to update user \"%s\" (error %lu).", userName, errorCode);
  421. }
  422. }
  423. return errorCode;
  424. }