Bugfix: user password was not saved to database after password change
[public/netxms.git] / src / server / core / users.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003, 2004 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** $module: users.cpp
20 **
21 **/
22
23 #include "nms_core.h"
24
25
26 //
27 // Global variables
28 //
29
30 NMS_USER *g_pUserList = NULL;
31 DWORD g_dwNumUsers = 0;
32 NMS_USER_GROUP *g_pGroupList = NULL;
33 DWORD g_dwNumGroups = 0;
34
35
36 //
37 // Static data
38 //
39
40 static MUTEX m_hMutexUserAccess;
41 static MUTEX m_hMutexGroupAccess;
42
43
44 //
45 // Initialize user handling subsystem
46 //
47
48 void InitUsers(void)
49 {
50 m_hMutexUserAccess = MutexCreate();
51 m_hMutexGroupAccess = MutexCreate();
52 }
53
54
55 //
56 // Load user list from database
57 //
58
59 BOOL LoadUsers(void)
60 {
61 DB_RESULT hResult;
62 DWORD i, iNumRows;
63
64 // Load users
65 hResult = DBSelect(g_hCoreDB, "SELECT id,name,password,access,flags,full_name,description FROM users ORDER BY id");
66 if (hResult == NULL)
67 return FALSE;
68
69 g_dwNumUsers = DBGetNumRows(hResult);
70 g_pUserList = (NMS_USER *)malloc(sizeof(NMS_USER) * g_dwNumUsers);
71 for(i = 0; i < g_dwNumUsers; i++)
72 {
73 g_pUserList[i].dwId = DBGetFieldULong(hResult, i, 0);
74 strncpy(g_pUserList[i].szName, DBGetField(hResult, i, 1), MAX_USER_NAME);
75 if (StrToBin(DBGetField(hResult, i, 2), g_pUserList[i].szPassword, SHA1_DIGEST_SIZE) != SHA1_DIGEST_SIZE)
76 {
77 WriteLog(MSG_INVALID_SHA1_HASH, EVENTLOG_WARNING_TYPE, "s", g_pUserList[i].szName);
78 CalculateSHA1Hash((BYTE *)"netxms", 6, g_pUserList[i].szPassword);
79 }
80 if (g_pUserList[i].dwId == 0)
81 g_pUserList[i].wSystemRights = SYSTEM_ACCESS_FULL; // Ignore database value for superuser
82 else
83 g_pUserList[i].wSystemRights = (WORD)DBGetFieldLong(hResult, i, 3);
84 g_pUserList[i].wFlags = (WORD)DBGetFieldLong(hResult, i, 4);
85 strncpy(g_pUserList[i].szFullName, DBGetField(hResult, i, 5), MAX_USER_FULLNAME);
86 strncpy(g_pUserList[i].szDescription, DBGetField(hResult, i, 6), MAX_USER_DESCR);
87 }
88
89 DBFreeResult(hResult);
90
91 // Check if user with UID 0 was loaded
92 for(i = 0; i < g_dwNumUsers; i++)
93 if (g_pUserList[i].dwId == 0)
94 break;
95 // Create superuser account if it doesn't exist
96 if (i == g_dwNumUsers)
97 {
98 g_dwNumUsers++;
99 g_pUserList = (NMS_USER *)realloc(g_pUserList, sizeof(NMS_USER) * g_dwNumUsers);
100 g_pUserList[i].dwId = 0;
101 strcpy(g_pUserList[i].szName, "admin");
102 g_pUserList[i].wFlags = UF_MODIFIED | UF_CHANGE_PASSWORD;
103 g_pUserList[i].wSystemRights = SYSTEM_ACCESS_FULL;
104 g_pUserList[i].szFullName[0] = 0;
105 strcpy(g_pUserList[i].szDescription, "Built-in system administrator account");
106 CalculateSHA1Hash((BYTE *)"netxms", 6, g_pUserList[i].szPassword);
107 WriteLog(MSG_SUPERUSER_CREATED, EVENTLOG_WARNING_TYPE, NULL);
108 }
109
110 // Load groups
111 hResult = DBSelect(g_hCoreDB, "SELECT id,name,access,flags,description FROM user_groups ORDER BY id");
112 if (hResult == 0)
113 return FALSE;
114
115 g_dwNumGroups = DBGetNumRows(hResult);
116 g_pGroupList = (NMS_USER_GROUP *)malloc(sizeof(NMS_USER_GROUP) * g_dwNumGroups);
117 for(i = 0; i < g_dwNumGroups; i++)
118 {
119 g_pGroupList[i].dwId = DBGetFieldULong(hResult, i, 0);
120 strncpy(g_pGroupList[i].szName, DBGetField(hResult, i, 1), MAX_USER_NAME);
121 g_pGroupList[i].wSystemRights = (WORD)DBGetFieldLong(hResult, i, 2);
122 g_pGroupList[i].wFlags = (WORD)DBGetFieldLong(hResult, i, 3);
123 strncpy(g_pGroupList[i].szDescription, DBGetField(hResult, i, 4), MAX_USER_DESCR);
124 g_pGroupList[i].dwNumMembers = 0;
125 g_pGroupList[i].pMembers = NULL;
126 }
127
128 DBFreeResult(hResult);
129
130 // Check if everyone group was loaded
131 for(i = 0; i < g_dwNumGroups; i++)
132 if (g_pGroupList[i].dwId == GROUP_EVERYONE)
133 break;
134 // Create everyone group if it doesn't exist
135 if (i == g_dwNumGroups)
136 {
137 g_dwNumGroups++;
138 g_pGroupList = (NMS_USER_GROUP *)realloc(g_pGroupList, sizeof(NMS_USER_GROUP) * g_dwNumGroups);
139 g_pGroupList[i].dwId = GROUP_EVERYONE;
140 g_pGroupList[i].dwNumMembers = 0;
141 g_pGroupList[i].pMembers = NULL;
142 strcpy(g_pGroupList[i].szName, "Everyone");
143 g_pGroupList[i].wFlags = UF_MODIFIED;
144 g_pGroupList[i].wSystemRights = 0;
145 strcpy(g_pGroupList[i].szDescription, "Built-in everyone group");
146 WriteLog(MSG_EVERYONE_GROUP_CREATED, EVENTLOG_WARNING_TYPE, NULL);
147 }
148
149 // Add users to groups
150 hResult = DBSelect(g_hCoreDB, "SELECT user_id,group_id FROM user_group_members");
151 if (hResult == 0)
152 return FALSE;
153
154 iNumRows = DBGetNumRows(hResult);
155 for(i = 0; i < iNumRows; i++)
156 AddUserToGroup(DBGetFieldULong(hResult, i, 0), DBGetFieldULong(hResult, i, 1));
157
158 return TRUE;
159 }
160
161
162 //
163 // Save user list to database
164 //
165
166 void SaveUsers(void)
167 {
168 DWORD i;
169 char szQuery[1024], szPassword[SHA1_DIGEST_SIZE * 2 + 1];
170
171 // Save users
172 MutexLock(m_hMutexUserAccess, INFINITE);
173 for(i = 0; i < g_dwNumUsers; i++)
174 {
175 if (g_pUserList[i].wFlags & UF_DELETED)
176 {
177 // Delete user record from database
178 sprintf(szQuery, "DELETE FROM users WHERE id=%d", g_pUserList[i].dwId);
179 DBQuery(g_hCoreDB, szQuery);
180
181 // Delete user record from memory
182 g_dwNumUsers--;
183 memmove(&g_pUserList[i], &g_pUserList[i + 1], sizeof(NMS_USER) * (g_dwNumUsers - i));
184 i--;
185 }
186 else if (g_pUserList[i].wFlags & UF_MODIFIED)
187 {
188 DB_RESULT hResult;
189 BOOL bUserExists = FALSE;
190
191 // Clear modification flag
192 g_pUserList[i].wFlags &= ~UF_MODIFIED;
193
194 // Check if user record exists in database
195 sprintf(szQuery, "SELECT name FROM users WHERE id=%d", g_pUserList[i].dwId);
196 hResult = DBSelect(g_hCoreDB, szQuery);
197 if (hResult != NULL)
198 {
199 if (DBGetNumRows(hResult) != 0)
200 bUserExists = TRUE;
201 DBFreeResult(hResult);
202 }
203
204 // Create or update record in database
205 BinToStr(g_pUserList[i].szPassword, SHA1_DIGEST_SIZE, szPassword);
206 if (bUserExists)
207 sprintf(szQuery, "UPDATE users SET name='%s',password='%s',access=%d,flags=%d,"
208 "full_name='%s',description='%s' WHERE id=%d",
209 g_pUserList[i].szName, szPassword, g_pUserList[i].wSystemRights,
210 g_pUserList[i].wFlags, g_pUserList[i].szFullName,
211 g_pUserList[i].szDescription, g_pUserList[i].dwId);
212 else
213 sprintf(szQuery, "INSERT INTO users (id,name,password,access,flags,full_name,description) "
214 "VALUES (%d,'%s','%s',%d,%d,'%s','%s')",
215 g_pUserList[i].dwId, g_pUserList[i].szName, szPassword,
216 g_pUserList[i].wSystemRights, g_pUserList[i].wFlags,
217 g_pUserList[i].szFullName, g_pUserList[i].szDescription);
218 DBQuery(g_hCoreDB, szQuery);
219 }
220 }
221 MutexUnlock(m_hMutexUserAccess);
222
223 // Save groups
224 MutexLock(m_hMutexGroupAccess, INFINITE);
225 for(i = 0; i < g_dwNumGroups; i++)
226 {
227 if (g_pGroupList[i].wFlags & UF_DELETED)
228 {
229 // Delete group record from database
230 sprintf(szQuery, "DELETE FROM user_groups WHERE id=%d", g_pGroupList[i].dwId);
231 DBQuery(g_hCoreDB, szQuery);
232 sprintf(szQuery, "DELETE FROM user_group_members WHERE group_id=%d", g_pGroupList[i].dwId);
233 DBQuery(g_hCoreDB, szQuery);
234
235 // Delete group record from memory
236 if (g_pGroupList[i].pMembers != NULL)
237 free(g_pGroupList[i].pMembers);
238 g_dwNumGroups--;
239 memmove(&g_pGroupList[i], &g_pGroupList[i + 1], sizeof(NMS_USER_GROUP) * (g_dwNumGroups - i));
240 i--;
241 }
242 else if (g_pGroupList[i].wFlags & UF_MODIFIED)
243 {
244 DB_RESULT hResult;
245 BOOL bGroupExists = FALSE;
246
247 // Clear modification flag
248 g_pGroupList[i].wFlags &= ~UF_MODIFIED;
249
250 // Check if group record exists in database
251 sprintf(szQuery, "SELECT name FROM user_groups WHERE id=%d", g_pGroupList[i].dwId);
252 hResult = DBSelect(g_hCoreDB, szQuery);
253 if (hResult != NULL)
254 {
255 if (DBGetNumRows(hResult) != 0)
256 bGroupExists = TRUE;
257 DBFreeResult(hResult);
258 }
259
260 // Create or update record in database
261 if (bGroupExists)
262 sprintf(szQuery, "UPDATE user_groups SET name='%s',access=%d,flags=%d,"
263 "description='%s' WHERE id=%d",
264 g_pGroupList[i].szName, g_pGroupList[i].wSystemRights,
265 g_pGroupList[i].wFlags, g_pGroupList[i].szDescription,
266 g_pGroupList[i].dwId);
267 else
268 sprintf(szQuery, "INSERT INTO user_groups (id,name,access,flags,description) "
269 "VALUES (%d,'%s',%d,%d,'%s')",
270 g_pGroupList[i].dwId, g_pGroupList[i].szName, g_pGroupList[i].wSystemRights,
271 g_pGroupList[i].wFlags, g_pGroupList[i].szDescription);
272 DBQuery(g_hCoreDB, szQuery);
273
274 if (bGroupExists)
275 {
276 sprintf(szQuery, "DELETE FROM user_group_members WHERE group_id=%d", g_pGroupList[i].dwId);
277 DBQuery(g_hCoreDB, szQuery);
278 }
279
280 for(DWORD j = 0; j < g_pGroupList[i].dwNumMembers; j++)
281 {
282 sprintf(szQuery, "INSERT INTO user_group_members (group_id, user_id) VALUES (%d, %d)",
283 g_pGroupList[i].dwId, g_pGroupList[i].pMembers[j]);
284 DBQuery(g_hCoreDB, szQuery);
285 }
286 }
287 }
288 MutexUnlock(m_hMutexGroupAccess);
289 }
290
291
292 //
293 // Authenticate user
294 // Checks if provided login name and password are correct, and returns TRUE
295 // on success and FALSE otherwise. On success authentication, user's ID is stored
296 // int pdwId.
297 //
298
299 BOOL AuthenticateUser(char *szName, BYTE *szPassword, DWORD *pdwId, DWORD *pdwSystemRights)
300 {
301 DWORD i;
302 BOOL bResult = FALSE;
303
304 MutexLock(m_hMutexUserAccess, INFINITE);
305 for(i = 0; i < g_dwNumUsers; i++)
306 {
307 if (!strcmp(szName, g_pUserList[i].szName) &&
308 !memcmp(szPassword, g_pUserList[i].szPassword, SHA1_DIGEST_SIZE) &&
309 !(g_pUserList[i].wFlags & UF_DELETED) && !(g_pUserList[i].wFlags & UF_DISABLED))
310 {
311 *pdwId = g_pUserList[i].dwId;
312 *pdwSystemRights = (DWORD)g_pUserList[i].wSystemRights;
313 bResult = TRUE;
314 break;
315 }
316 }
317 MutexUnlock(m_hMutexUserAccess);
318 return bResult;
319 }
320
321
322 //
323 // Add user to group
324 //
325
326 void AddUserToGroup(DWORD dwUserId, DWORD dwGroupId)
327 {
328 DWORD i;
329
330 MutexLock(m_hMutexGroupAccess, INFINITE);
331
332 // Find group
333 for(i = 0; i < g_dwNumGroups; i++)
334 if (g_pGroupList[i].dwId == dwGroupId)
335 break;
336
337 if (i != g_dwNumGroups)
338 {
339 DWORD j;
340
341 // Check if user already in group
342 for(j = 0; j < g_pGroupList[i].dwNumMembers; j++)
343 if (g_pGroupList[i].pMembers[j] == dwUserId)
344 break;
345
346 // If not in group, add it
347 if (j == g_pGroupList[i].dwNumMembers)
348 {
349 g_pGroupList[i].dwNumMembers++;
350 g_pGroupList[i].pMembers = (DWORD *)realloc(g_pGroupList[i].pMembers,
351 sizeof(DWORD) * g_pGroupList[i].dwNumMembers);
352 g_pGroupList[i].pMembers[j] = dwUserId;
353 }
354 }
355
356 MutexUnlock(m_hMutexGroupAccess);
357 }
358
359
360 //
361 // Delete user from group
362 //
363
364 static void DeleteUserFromGroup(NMS_USER_GROUP *pGroup, DWORD dwUserId)
365 {
366 DWORD i;
367
368 for(i = 0; i < pGroup->dwNumMembers; i++)
369 if (pGroup->pMembers[i] == dwUserId)
370 {
371 pGroup->dwNumMembers--;
372 memmove(&pGroup->pMembers[i], &pGroup->pMembers[i + 1], sizeof(DWORD) * (pGroup->dwNumMembers - i));
373 }
374 }
375
376
377 //
378 // Check if user is a member of specific group
379 //
380
381 BOOL CheckUserMembership(DWORD dwUserId, DWORD dwGroupId)
382 {
383 BOOL bResult = FALSE;
384
385 MutexLock(m_hMutexGroupAccess, INFINITE);
386 if (dwGroupId == GROUP_EVERYONE)
387 {
388 bResult = TRUE;
389 }
390 else
391 {
392 DWORD i, j;
393
394 // Find group
395 for(i = 0; i < g_dwNumGroups; i++)
396 if (g_pGroupList[i].dwId == dwGroupId)
397 {
398 // Walk through group members
399 for(j = 0; j < g_pGroupList[i].dwNumMembers; j++)
400 if (g_pGroupList[i].pMembers[j] == dwUserId)
401 {
402 bResult = TRUE;
403 break;
404 }
405 break;
406 }
407 }
408 MutexUnlock(m_hMutexGroupAccess);
409 return bResult;
410 }
411
412
413 //
414 // Dump user list to stdout
415 //
416
417 void DumpUsers(void)
418 {
419 DWORD i;
420
421 printf("Login name System rights\n"
422 "----------------------------------\n");
423 for(i = 0; i < g_dwNumUsers; i++)
424 printf("%-20s 0x%08X\n", g_pUserList[i].szName, g_pUserList[i].wSystemRights);
425 printf("\n");
426 }
427
428
429 //
430 // Delete user or group
431 // Will return RCC code
432 //
433
434 DWORD DeleteUserFromDB(DWORD dwId)
435 {
436 DWORD i, j;
437
438 DeleteUserFromAllObjects(dwId);
439
440 if (dwId & GROUP_FLAG)
441 {
442 MutexLock(m_hMutexGroupAccess, INFINITE);
443
444 // Find group
445 for(i = 0; i < g_dwNumGroups; i++)
446 if (g_pGroupList[i].dwId == dwId)
447 {
448 g_pGroupList[i].dwNumMembers = 0;
449 safe_free(g_pGroupList[i].pMembers);
450 g_pGroupList[i].pMembers = NULL;
451 g_pGroupList[i].wFlags |= UF_DELETED;
452 break;
453 }
454
455 MutexUnlock(m_hMutexGroupAccess);
456 }
457 else
458 {
459 MutexLock(m_hMutexUserAccess, INFINITE);
460
461 // Find user
462 for(i = 0; i < g_dwNumUsers; i++)
463 if (g_pUserList[i].dwId == dwId)
464 {
465 g_pUserList[i].wFlags |= UF_DELETED;
466
467 // Delete this user from all groups
468 MutexLock(m_hMutexGroupAccess, INFINITE);
469 for(j = 0; j < g_dwNumGroups; j++)
470 DeleteUserFromGroup(&g_pGroupList[i], dwId);
471 MutexUnlock(m_hMutexGroupAccess);
472 break;
473 }
474
475 MutexUnlock(m_hMutexUserAccess);
476 }
477
478 SendUserDBUpdate(USER_DB_DELETE, dwId, NULL, NULL);
479
480 return RCC_SUCCESS;
481 }
482
483
484 //
485 // Create new user or group
486 //
487
488 DWORD CreateNewUser(char *pszName, BOOL bIsGroup, DWORD *pdwId)
489 {
490 DWORD i, dwResult = RCC_SUCCESS;
491 DWORD dwNewId;
492
493 if (bIsGroup)
494 {
495 MutexLock(m_hMutexGroupAccess, INFINITE);
496
497 // Check for duplicate name
498 for(i = 0; i < g_dwNumGroups; i++)
499 if (!stricmp(g_pGroupList[i].szName, pszName))
500 {
501 dwResult = RCC_ALREADY_EXIST;
502 break;
503 }
504
505 // If not exist, create it
506 if (i == g_dwNumGroups)
507 {
508 g_dwNumGroups++;
509 g_pGroupList = (NMS_USER_GROUP *)realloc(g_pGroupList, sizeof(NMS_USER_GROUP) * g_dwNumGroups);
510 g_pGroupList[i].dwId = dwNewId = CreateUniqueId(IDG_USER_GROUP);
511 g_pGroupList[i].dwNumMembers = 0;
512 g_pGroupList[i].pMembers = NULL;
513 strncpy(g_pGroupList[i].szName, pszName, MAX_USER_NAME);
514 g_pGroupList[i].wFlags = UF_MODIFIED;
515 g_pGroupList[i].wSystemRights = 0;
516 g_pGroupList[i].szDescription[0] = 0;
517 }
518
519 if (dwResult == RCC_SUCCESS)
520 SendUserDBUpdate(USER_DB_CREATE, dwNewId, NULL, &g_pGroupList[i]);
521
522 MutexUnlock(m_hMutexGroupAccess);
523 }
524 else
525 {
526 MutexLock(m_hMutexUserAccess, INFINITE);
527
528 // Check for duplicate name
529 for(i = 0; i < g_dwNumUsers; i++)
530 if (!stricmp(g_pUserList[i].szName, pszName))
531 {
532 dwResult = RCC_ALREADY_EXIST;
533 break;
534 }
535
536 // If not exist, create it
537 if (i == g_dwNumUsers)
538 {
539 g_dwNumUsers++;
540 g_pUserList = (NMS_USER *)realloc(g_pUserList, sizeof(NMS_USER) * g_dwNumUsers);
541 g_pUserList[i].dwId = dwNewId = CreateUniqueId(IDG_USER);
542 strncpy(g_pUserList[i].szName, pszName, MAX_USER_NAME);
543 g_pUserList[i].wFlags = UF_MODIFIED;
544 g_pUserList[i].wSystemRights = 0;
545 g_pUserList[i].szFullName[0] = 0;
546 g_pUserList[i].szDescription[0] = 0;
547 }
548
549 if (dwResult == RCC_SUCCESS)
550 SendUserDBUpdate(USER_DB_CREATE, dwNewId, &g_pUserList[i], NULL);
551
552 MutexUnlock(m_hMutexUserAccess);
553 }
554
555 *pdwId = dwNewId;
556
557 return dwResult;
558 }
559
560
561 //
562 // Modify user record
563 //
564
565 DWORD ModifyUser(NMS_USER *pUserInfo)
566 {
567 DWORD i, dwResult = RCC_INVALID_USER_ID;
568
569 MutexLock(m_hMutexUserAccess, INFINITE);
570
571 // Find user to be modified in list
572 for(i = 0; i < g_dwNumUsers; i++)
573 if (g_pUserList[i].dwId == pUserInfo->dwId)
574 {
575 if (!IsValidObjectName(pUserInfo->szName))
576 {
577 dwResult = RCC_INVALID_OBJECT_NAME;
578 break;
579 }
580
581 strcpy(g_pUserList[i].szName, pUserInfo->szName);
582 strcpy(g_pUserList[i].szFullName, pUserInfo->szFullName);
583 strcpy(g_pUserList[i].szDescription, pUserInfo->szDescription);
584
585 // We will not replace system access rights for UID 0
586 if (g_pUserList[i].dwId != 0)
587 g_pUserList[i].wSystemRights = pUserInfo->wSystemRights;
588
589 // Modify UF_DISABLED and UF_CHANGE_PASSWORD flags from pUserInfo
590 // Ignore DISABLED flag for UID 0
591 g_pUserList[i].wFlags &= ~(UF_DISABLED | UF_CHANGE_PASSWORD);
592 if (g_pUserList[i].dwId == 0)
593 g_pUserList[i].wFlags |= pUserInfo->wFlags & UF_CHANGE_PASSWORD;
594 else
595 g_pUserList[i].wFlags |= pUserInfo->wFlags & (UF_DISABLED | UF_CHANGE_PASSWORD);
596
597 // Mark user record as modified and notify clients
598 g_pUserList[i].wFlags |= UF_MODIFIED;
599 SendUserDBUpdate(USER_DB_MODIFY, g_pUserList[i].dwId, &g_pUserList[i], NULL);
600 dwResult = RCC_SUCCESS;
601 break;
602 }
603
604 MutexUnlock(m_hMutexUserAccess);
605 return dwResult;
606 }
607
608
609 //
610 // Modify group record
611 //
612
613 DWORD ModifyGroup(NMS_USER_GROUP *pGroupInfo)
614 {
615 DWORD i, dwResult = RCC_INVALID_USER_ID;
616
617 MutexLock(m_hMutexGroupAccess, INFINITE);
618
619 // Find group in list
620 for(i = 0; i < g_dwNumGroups; i++)
621 if (g_pGroupList[i].dwId == pGroupInfo->dwId)
622 {
623 if (!IsValidObjectName(pGroupInfo->szName))
624 {
625 dwResult = RCC_INVALID_OBJECT_NAME;
626 break;
627 }
628
629 strcpy(g_pGroupList[i].szName, pGroupInfo->szName);
630 strcpy(g_pGroupList[i].szDescription, pGroupInfo->szDescription);
631 g_pGroupList[i].wSystemRights = pGroupInfo->wSystemRights;
632
633 // Ignore DISABLED flag for EVERYONE group
634 if (g_pGroupList[i].dwId != 0)
635 {
636 g_pGroupList[i].wFlags &= ~UF_DISABLED;
637 g_pGroupList[i].wFlags |= pGroupInfo->wFlags & UF_DISABLED;
638 }
639
640 // Modify members list
641 g_pGroupList[i].dwNumMembers = pGroupInfo->dwNumMembers;
642 g_pGroupList[i].pMembers = (DWORD *)realloc(g_pGroupList[i].pMembers, sizeof(DWORD) * g_pGroupList[i].dwNumMembers);
643 memcpy(g_pGroupList[i].pMembers, pGroupInfo->pMembers, sizeof(DWORD) * g_pGroupList[i].dwNumMembers);
644
645 // Mark group record as modified and notify clients
646 g_pGroupList[i].wFlags |= UF_MODIFIED;
647 SendUserDBUpdate(USER_DB_MODIFY, g_pGroupList[i].dwId, NULL, &g_pGroupList[i]);
648 dwResult = RCC_SUCCESS;
649 break;
650 }
651
652 MutexUnlock(m_hMutexGroupAccess);
653 return dwResult;
654 }
655
656
657 //
658 // Set user's password
659 //
660
661 DWORD SetUserPassword(DWORD dwId, BYTE *pszPassword)
662 {
663 DWORD i, dwResult = RCC_INVALID_USER_ID;
664
665 MutexLock(m_hMutexUserAccess, INFINITE);
666
667 // Find user
668 for(i = 0; i < g_dwNumUsers; i++)
669 if (g_pUserList[i].dwId == dwId)
670 {
671 memcpy(g_pUserList[i].szPassword, pszPassword, SHA1_DIGEST_SIZE);
672 g_pUserList[i].wFlags |= UF_MODIFIED;
673 dwResult = RCC_SUCCESS;
674 break;
675 }
676
677 MutexUnlock(m_hMutexUserAccess);
678 return dwResult;
679 }