e832b43f35b901f0a3d66f3cc8b70bf24fa4631b
[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 "nxcore.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,system_access,flags,full_name,description,grace_logins 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 nx_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 nx_strncpy(g_pUserList[i].szFullName, DBGetField(hResult, i, 5), MAX_USER_FULLNAME);
86 nx_strncpy(g_pUserList[i].szDescription, DBGetField(hResult, i, 6), MAX_USER_DESCR);
87 g_pUserList[i].nGraceLogins = DBGetFieldLong(hResult, i, 7);
88 }
89
90 DBFreeResult(hResult);
91
92 // Check if user with UID 0 was loaded
93 for(i = 0; i < g_dwNumUsers; i++)
94 if (g_pUserList[i].dwId == 0)
95 break;
96 // Create superuser account if it doesn't exist
97 if (i == g_dwNumUsers)
98 {
99 g_dwNumUsers++;
100 g_pUserList = (NMS_USER *)realloc(g_pUserList, sizeof(NMS_USER) * g_dwNumUsers);
101 g_pUserList[i].dwId = 0;
102 strcpy(g_pUserList[i].szName, "admin");
103 g_pUserList[i].wFlags = UF_MODIFIED | UF_CHANGE_PASSWORD;
104 g_pUserList[i].wSystemRights = SYSTEM_ACCESS_FULL;
105 g_pUserList[i].szFullName[0] = 0;
106 strcpy(g_pUserList[i].szDescription, "Built-in system administrator account");
107 CalculateSHA1Hash((BYTE *)"netxms", 6, g_pUserList[i].szPassword);
108 g_pUserList[i].nGraceLogins = MAX_GRACE_LOGINS;
109 WriteLog(MSG_SUPERUSER_CREATED, EVENTLOG_WARNING_TYPE, NULL);
110 }
111
112 // Load groups
113 hResult = DBSelect(g_hCoreDB, "SELECT id,name,system_access,flags,description FROM user_groups ORDER BY id");
114 if (hResult == 0)
115 return FALSE;
116
117 g_dwNumGroups = DBGetNumRows(hResult);
118 g_pGroupList = (NMS_USER_GROUP *)malloc(sizeof(NMS_USER_GROUP) * g_dwNumGroups);
119 for(i = 0; i < g_dwNumGroups; i++)
120 {
121 g_pGroupList[i].dwId = DBGetFieldULong(hResult, i, 0);
122 nx_strncpy(g_pGroupList[i].szName, DBGetField(hResult, i, 1), MAX_USER_NAME);
123 g_pGroupList[i].wSystemRights = (WORD)DBGetFieldLong(hResult, i, 2);
124 g_pGroupList[i].wFlags = (WORD)DBGetFieldLong(hResult, i, 3);
125 nx_strncpy(g_pGroupList[i].szDescription, DBGetField(hResult, i, 4), MAX_USER_DESCR);
126 g_pGroupList[i].dwNumMembers = 0;
127 g_pGroupList[i].pMembers = NULL;
128 }
129
130 DBFreeResult(hResult);
131
132 // Check if everyone group was loaded
133 for(i = 0; i < g_dwNumGroups; i++)
134 if (g_pGroupList[i].dwId == GROUP_EVERYONE)
135 break;
136 // Create everyone group if it doesn't exist
137 if (i == g_dwNumGroups)
138 {
139 g_dwNumGroups++;
140 g_pGroupList = (NMS_USER_GROUP *)realloc(g_pGroupList, sizeof(NMS_USER_GROUP) * g_dwNumGroups);
141 g_pGroupList[i].dwId = GROUP_EVERYONE;
142 g_pGroupList[i].dwNumMembers = 0;
143 g_pGroupList[i].pMembers = NULL;
144 strcpy(g_pGroupList[i].szName, "Everyone");
145 g_pGroupList[i].wFlags = UF_MODIFIED;
146 g_pGroupList[i].wSystemRights = 0;
147 strcpy(g_pGroupList[i].szDescription, "Built-in everyone group");
148 WriteLog(MSG_EVERYONE_GROUP_CREATED, EVENTLOG_WARNING_TYPE, NULL);
149 }
150
151 // Add users to groups
152 hResult = DBSelect(g_hCoreDB, "SELECT user_id,group_id FROM user_group_members");
153 if (hResult == 0)
154 return FALSE;
155
156 iNumRows = DBGetNumRows(hResult);
157 for(i = 0; i < iNumRows; i++)
158 AddUserToGroup(DBGetFieldULong(hResult, i, 0), DBGetFieldULong(hResult, i, 1));
159
160 return TRUE;
161 }
162
163
164 //
165 // Save user list to database
166 //
167
168 void SaveUsers(DB_HANDLE hdb)
169 {
170 DWORD i;
171 char szQuery[1024], szPassword[SHA1_DIGEST_SIZE * 2 + 1];
172
173 // Save users
174 MutexLock(m_hMutexUserAccess, INFINITE);
175 for(i = 0; i < g_dwNumUsers; i++)
176 {
177 if (g_pUserList[i].wFlags & UF_DELETED)
178 {
179 // Delete user record from database
180 sprintf(szQuery, "DELETE FROM users WHERE id=%d", g_pUserList[i].dwId);
181 DBQuery(hdb, szQuery);
182 sprintf(szQuery, "DELETE FROM user_profiles WHERE user_id=%d", g_pUserList[i].dwId);
183 DBQuery(hdb, szQuery);
184
185 // Delete user record from memory
186 g_dwNumUsers--;
187 memmove(&g_pUserList[i], &g_pUserList[i + 1], sizeof(NMS_USER) * (g_dwNumUsers - i));
188 i--;
189 }
190 else if (g_pUserList[i].wFlags & UF_MODIFIED)
191 {
192 DB_RESULT hResult;
193 BOOL bUserExists = FALSE;
194
195 // Clear modification flag
196 g_pUserList[i].wFlags &= ~UF_MODIFIED;
197
198 // Check if user record exists in database
199 sprintf(szQuery, "SELECT name FROM users WHERE id=%d", g_pUserList[i].dwId);
200 hResult = DBSelect(hdb, szQuery);
201 if (hResult != NULL)
202 {
203 if (DBGetNumRows(hResult) != 0)
204 bUserExists = TRUE;
205 DBFreeResult(hResult);
206 }
207
208 // Create or update record in database
209 BinToStr(g_pUserList[i].szPassword, SHA1_DIGEST_SIZE, szPassword);
210 if (bUserExists)
211 sprintf(szQuery, "UPDATE users SET name='%s',password='%s',system_access=%d,flags=%d,"
212 "full_name='%s',description='%s',grace_logins=%d WHERE id=%d",
213 g_pUserList[i].szName, szPassword, g_pUserList[i].wSystemRights,
214 g_pUserList[i].wFlags, g_pUserList[i].szFullName,
215 g_pUserList[i].szDescription, g_pUserList[i].nGraceLogins,
216 g_pUserList[i].dwId);
217 else
218 sprintf(szQuery, "INSERT INTO users (id,name,password,system_access,flags,full_name,description,grace_logins) "
219 "VALUES (%d,'%s','%s',%d,%d,'%s','%s',%d)",
220 g_pUserList[i].dwId, g_pUserList[i].szName, szPassword,
221 g_pUserList[i].wSystemRights, g_pUserList[i].wFlags,
222 g_pUserList[i].szFullName, g_pUserList[i].szDescription,
223 g_pUserList[i].nGraceLogins);
224 DBQuery(hdb, szQuery);
225 }
226 }
227 MutexUnlock(m_hMutexUserAccess);
228
229 // Save groups
230 MutexLock(m_hMutexGroupAccess, INFINITE);
231 for(i = 0; i < g_dwNumGroups; i++)
232 {
233 if (g_pGroupList[i].wFlags & UF_DELETED)
234 {
235 // Delete group record from database
236 sprintf(szQuery, "DELETE FROM user_groups WHERE id=%d", g_pGroupList[i].dwId);
237 DBQuery(hdb, szQuery);
238 sprintf(szQuery, "DELETE FROM user_group_members WHERE group_id=%d", g_pGroupList[i].dwId);
239 DBQuery(hdb, szQuery);
240
241 // Delete group record from memory
242 if (g_pGroupList[i].pMembers != NULL)
243 free(g_pGroupList[i].pMembers);
244 g_dwNumGroups--;
245 memmove(&g_pGroupList[i], &g_pGroupList[i + 1], sizeof(NMS_USER_GROUP) * (g_dwNumGroups - i));
246 i--;
247 }
248 else if (g_pGroupList[i].wFlags & UF_MODIFIED)
249 {
250 DB_RESULT hResult;
251 BOOL bGroupExists = FALSE;
252
253 // Clear modification flag
254 g_pGroupList[i].wFlags &= ~UF_MODIFIED;
255
256 // Check if group record exists in database
257 sprintf(szQuery, "SELECT name FROM user_groups WHERE id=%d", g_pGroupList[i].dwId);
258 hResult = DBSelect(hdb, szQuery);
259 if (hResult != NULL)
260 {
261 if (DBGetNumRows(hResult) != 0)
262 bGroupExists = TRUE;
263 DBFreeResult(hResult);
264 }
265
266 // Create or update record in database
267 if (bGroupExists)
268 sprintf(szQuery, "UPDATE user_groups SET name='%s',system_access=%d,flags=%d,"
269 "description='%s' WHERE id=%d",
270 g_pGroupList[i].szName, g_pGroupList[i].wSystemRights,
271 g_pGroupList[i].wFlags, g_pGroupList[i].szDescription,
272 g_pGroupList[i].dwId);
273 else
274 sprintf(szQuery, "INSERT INTO user_groups (id,name,system_access,flags,description) "
275 "VALUES (%d,'%s',%d,%d,'%s')",
276 g_pGroupList[i].dwId, g_pGroupList[i].szName, g_pGroupList[i].wSystemRights,
277 g_pGroupList[i].wFlags, g_pGroupList[i].szDescription);
278 DBQuery(hdb, szQuery);
279
280 if (bGroupExists)
281 {
282 sprintf(szQuery, "DELETE FROM user_group_members WHERE group_id=%d", g_pGroupList[i].dwId);
283 DBQuery(hdb, szQuery);
284 }
285
286 for(DWORD j = 0; j < g_pGroupList[i].dwNumMembers; j++)
287 {
288 sprintf(szQuery, "INSERT INTO user_group_members (group_id, user_id) VALUES (%d, %d)",
289 g_pGroupList[i].dwId, g_pGroupList[i].pMembers[j]);
290 DBQuery(hdb, szQuery);
291 }
292 }
293 }
294 MutexUnlock(m_hMutexGroupAccess);
295 }
296
297
298 //
299 // Authenticate user
300 // Checks if provided login name and password are correct, and returns RCC_SUCCESS
301 // on success and appropriate RCC otherwise. On success authentication, user's ID is stored
302 // int pdwId.
303 //
304
305 DWORD AuthenticateUser(char *szName, BYTE *szPassword, DWORD *pdwId,
306 DWORD *pdwSystemRights, BOOL *pbChangePasswd)
307 {
308 DWORD i, j;
309 DWORD dwResult = RCC_ACCESS_DENIED;
310
311 MutexLock(m_hMutexUserAccess, INFINITE);
312 for(i = 0; i < g_dwNumUsers; i++)
313 {
314 if ((!strcmp(szName, g_pUserList[i].szName)) &&
315 (!(g_pUserList[i].wFlags & UF_DELETED)))
316 {
317 if (!memcmp(szPassword, g_pUserList[i].szPassword, SHA1_DIGEST_SIZE))
318 {
319 if (!(g_pUserList[i].wFlags & UF_DISABLED))
320 {
321 if (g_pUserList[i].wFlags & UF_CHANGE_PASSWORD)
322 {
323 if (g_pUserList[i].nGraceLogins <= 0)
324 {
325 dwResult = RCC_NO_GRACE_LOGINS;
326 break;
327 }
328 g_pUserList[i].nGraceLogins--;
329 *pbChangePasswd = TRUE;
330 }
331 else
332 {
333 *pbChangePasswd = FALSE;
334 }
335 *pdwId = g_pUserList[i].dwId;
336 *pdwSystemRights = (DWORD)g_pUserList[i].wSystemRights;
337 dwResult = RCC_SUCCESS;
338
339 // Collect system rights from groups this user belongs to
340 MutexLock(m_hMutexGroupAccess, INFINITE);
341 for(j = 0; j < g_dwNumGroups; j++)
342 if (CheckUserMembership(g_pUserList[i].dwId, g_pGroupList[j].dwId))
343 *pdwSystemRights |= (DWORD)g_pGroupList[j].wSystemRights;
344 MutexUnlock(m_hMutexGroupAccess);
345 }
346 else
347 {
348 dwResult = RCC_ACCOUNT_DISABLED;
349 }
350 }
351 break;
352 }
353 }
354 MutexUnlock(m_hMutexUserAccess);
355 return dwResult;
356 }
357
358
359 //
360 // Add user to group
361 //
362
363 void AddUserToGroup(DWORD dwUserId, DWORD dwGroupId)
364 {
365 DWORD i;
366
367 MutexLock(m_hMutexGroupAccess, INFINITE);
368
369 // Find group
370 for(i = 0; i < g_dwNumGroups; i++)
371 if (g_pGroupList[i].dwId == dwGroupId)
372 break;
373
374 if (i != g_dwNumGroups)
375 {
376 DWORD j;
377
378 // Check if user already in group
379 for(j = 0; j < g_pGroupList[i].dwNumMembers; j++)
380 if (g_pGroupList[i].pMembers[j] == dwUserId)
381 break;
382
383 // If not in group, add it
384 if (j == g_pGroupList[i].dwNumMembers)
385 {
386 g_pGroupList[i].dwNumMembers++;
387 g_pGroupList[i].pMembers = (DWORD *)realloc(g_pGroupList[i].pMembers,
388 sizeof(DWORD) * g_pGroupList[i].dwNumMembers);
389 g_pGroupList[i].pMembers[j] = dwUserId;
390 }
391 }
392
393 MutexUnlock(m_hMutexGroupAccess);
394 }
395
396
397 //
398 // Delete user from group
399 //
400
401 static void DeleteUserFromGroup(NMS_USER_GROUP *pGroup, DWORD dwUserId)
402 {
403 DWORD i;
404
405 for(i = 0; i < pGroup->dwNumMembers; i++)
406 if (pGroup->pMembers[i] == dwUserId)
407 {
408 pGroup->dwNumMembers--;
409 memmove(&pGroup->pMembers[i], &pGroup->pMembers[i + 1], sizeof(DWORD) * (pGroup->dwNumMembers - i));
410 }
411 }
412
413
414 //
415 // Check if user is a member of specific group
416 //
417
418 BOOL CheckUserMembership(DWORD dwUserId, DWORD dwGroupId)
419 {
420 BOOL bResult = FALSE;
421
422 MutexLock(m_hMutexGroupAccess, INFINITE);
423 if (dwGroupId == GROUP_EVERYONE)
424 {
425 bResult = TRUE;
426 }
427 else
428 {
429 DWORD i, j;
430
431 // Find group
432 for(i = 0; i < g_dwNumGroups; i++)
433 if (g_pGroupList[i].dwId == dwGroupId)
434 {
435 // Walk through group members
436 for(j = 0; j < g_pGroupList[i].dwNumMembers; j++)
437 if (g_pGroupList[i].pMembers[j] == dwUserId)
438 {
439 bResult = TRUE;
440 break;
441 }
442 break;
443 }
444 }
445 MutexUnlock(m_hMutexGroupAccess);
446 return bResult;
447 }
448
449
450 //
451 // Dump user list to stdout
452 //
453
454 void DumpUsers(CONSOLE_CTX pCtx)
455 {
456 DWORD i;
457
458 ConsolePrintf(pCtx, "Login name System rights\n"
459 "----------------------------------\n");
460 for(i = 0; i < g_dwNumUsers; i++)
461 ConsolePrintf(pCtx, "%-20s 0x%08X\n", g_pUserList[i].szName, g_pUserList[i].wSystemRights);
462 ConsolePrintf(pCtx, "\n");
463 }
464
465
466 //
467 // Delete user or group
468 // Will return RCC code
469 //
470
471 DWORD DeleteUserFromDB(DWORD dwId)
472 {
473 DWORD i, j;
474
475 DeleteUserFromAllObjects(dwId);
476
477 if (dwId & GROUP_FLAG)
478 {
479 MutexLock(m_hMutexGroupAccess, INFINITE);
480
481 // Find group
482 for(i = 0; i < g_dwNumGroups; i++)
483 if (g_pGroupList[i].dwId == dwId)
484 {
485 g_pGroupList[i].dwNumMembers = 0;
486 safe_free(g_pGroupList[i].pMembers);
487 g_pGroupList[i].pMembers = NULL;
488 g_pGroupList[i].wFlags |= UF_DELETED;
489 break;
490 }
491
492 MutexUnlock(m_hMutexGroupAccess);
493 }
494 else
495 {
496 MutexLock(m_hMutexUserAccess, INFINITE);
497
498 // Find user
499 for(i = 0; i < g_dwNumUsers; i++)
500 if (g_pUserList[i].dwId == dwId)
501 {
502 g_pUserList[i].wFlags |= UF_DELETED;
503
504 // Delete this user from all groups
505 MutexLock(m_hMutexGroupAccess, INFINITE);
506 for(j = 0; j < g_dwNumGroups; j++)
507 DeleteUserFromGroup(&g_pGroupList[i], dwId);
508 MutexUnlock(m_hMutexGroupAccess);
509 break;
510 }
511
512 MutexUnlock(m_hMutexUserAccess);
513 }
514
515 SendUserDBUpdate(USER_DB_DELETE, dwId, NULL, NULL);
516
517 return RCC_SUCCESS;
518 }
519
520
521 //
522 // Create new user or group
523 //
524
525 DWORD CreateNewUser(char *pszName, BOOL bIsGroup, DWORD *pdwId)
526 {
527 DWORD i, dwResult = RCC_SUCCESS;
528 DWORD dwNewId;
529
530 if (bIsGroup)
531 {
532 MutexLock(m_hMutexGroupAccess, INFINITE);
533
534 // Check for duplicate name
535 for(i = 0; i < g_dwNumGroups; i++)
536 if (!stricmp(g_pGroupList[i].szName, pszName))
537 {
538 dwResult = RCC_ALREADY_EXIST;
539 break;
540 }
541
542 // If not exist, create it
543 if (i == g_dwNumGroups)
544 {
545 g_dwNumGroups++;
546 g_pGroupList = (NMS_USER_GROUP *)realloc(g_pGroupList, sizeof(NMS_USER_GROUP) * g_dwNumGroups);
547 g_pGroupList[i].dwId = dwNewId = CreateUniqueId(IDG_USER_GROUP);
548 g_pGroupList[i].dwNumMembers = 0;
549 g_pGroupList[i].pMembers = NULL;
550 nx_strncpy(g_pGroupList[i].szName, pszName, MAX_USER_NAME);
551 g_pGroupList[i].wFlags = UF_MODIFIED;
552 g_pGroupList[i].wSystemRights = 0;
553 g_pGroupList[i].szDescription[0] = 0;
554 }
555
556 if (dwResult == RCC_SUCCESS)
557 SendUserDBUpdate(USER_DB_CREATE, dwNewId, NULL, &g_pGroupList[i]);
558
559 MutexUnlock(m_hMutexGroupAccess);
560 }
561 else
562 {
563 MutexLock(m_hMutexUserAccess, INFINITE);
564
565 // Check for duplicate name
566 for(i = 0; i < g_dwNumUsers; i++)
567 if (!stricmp(g_pUserList[i].szName, pszName))
568 {
569 dwResult = RCC_ALREADY_EXIST;
570 break;
571 }
572
573 // If not exist, create it
574 if (i == g_dwNumUsers)
575 {
576 g_dwNumUsers++;
577 g_pUserList = (NMS_USER *)realloc(g_pUserList, sizeof(NMS_USER) * g_dwNumUsers);
578 g_pUserList[i].dwId = dwNewId = CreateUniqueId(IDG_USER);
579 nx_strncpy(g_pUserList[i].szName, pszName, MAX_USER_NAME);
580 g_pUserList[i].wFlags = UF_MODIFIED;
581 g_pUserList[i].wSystemRights = 0;
582 g_pUserList[i].szFullName[0] = 0;
583 g_pUserList[i].szDescription[0] = 0;
584 g_pUserList[i].nGraceLogins = MAX_GRACE_LOGINS;
585 }
586
587 if (dwResult == RCC_SUCCESS)
588 SendUserDBUpdate(USER_DB_CREATE, dwNewId, &g_pUserList[i], NULL);
589
590 MutexUnlock(m_hMutexUserAccess);
591 }
592
593 *pdwId = dwNewId;
594
595 return dwResult;
596 }
597
598
599 //
600 // Modify user record
601 //
602
603 DWORD ModifyUser(NMS_USER *pUserInfo)
604 {
605 DWORD i, dwResult = RCC_INVALID_USER_ID;
606
607 MutexLock(m_hMutexUserAccess, INFINITE);
608
609 // Find user to be modified in list
610 for(i = 0; i < g_dwNumUsers; i++)
611 if (g_pUserList[i].dwId == pUserInfo->dwId)
612 {
613 if (!IsValidObjectName(pUserInfo->szName))
614 {
615 dwResult = RCC_INVALID_OBJECT_NAME;
616 break;
617 }
618
619 strcpy(g_pUserList[i].szName, pUserInfo->szName);
620 strcpy(g_pUserList[i].szFullName, pUserInfo->szFullName);
621 strcpy(g_pUserList[i].szDescription, pUserInfo->szDescription);
622
623 // We will not replace system access rights for UID 0
624 if (g_pUserList[i].dwId != 0)
625 g_pUserList[i].wSystemRights = pUserInfo->wSystemRights;
626
627 // Modify UF_DISABLED and UF_CHANGE_PASSWORD flags from pUserInfo
628 // Ignore DISABLED flag for UID 0
629 g_pUserList[i].wFlags &= ~(UF_DISABLED | UF_CHANGE_PASSWORD);
630 if (g_pUserList[i].dwId == 0)
631 g_pUserList[i].wFlags |= pUserInfo->wFlags & UF_CHANGE_PASSWORD;
632 else
633 g_pUserList[i].wFlags |= pUserInfo->wFlags & (UF_DISABLED | UF_CHANGE_PASSWORD);
634
635 // Mark user record as modified and notify clients
636 g_pUserList[i].wFlags |= UF_MODIFIED;
637 SendUserDBUpdate(USER_DB_MODIFY, g_pUserList[i].dwId, &g_pUserList[i], NULL);
638 dwResult = RCC_SUCCESS;
639 break;
640 }
641
642 MutexUnlock(m_hMutexUserAccess);
643 return dwResult;
644 }
645
646
647 //
648 // Modify group record
649 //
650
651 DWORD ModifyGroup(NMS_USER_GROUP *pGroupInfo)
652 {
653 DWORD i, dwResult = RCC_INVALID_USER_ID;
654
655 MutexLock(m_hMutexGroupAccess, INFINITE);
656
657 // Find group in list
658 for(i = 0; i < g_dwNumGroups; i++)
659 if (g_pGroupList[i].dwId == pGroupInfo->dwId)
660 {
661 if (!IsValidObjectName(pGroupInfo->szName))
662 {
663 dwResult = RCC_INVALID_OBJECT_NAME;
664 break;
665 }
666
667 strcpy(g_pGroupList[i].szName, pGroupInfo->szName);
668 strcpy(g_pGroupList[i].szDescription, pGroupInfo->szDescription);
669 g_pGroupList[i].wSystemRights = pGroupInfo->wSystemRights;
670
671 // Ignore DISABLED flag for EVERYONE group
672 if (g_pGroupList[i].dwId != 0)
673 {
674 g_pGroupList[i].wFlags &= ~UF_DISABLED;
675 g_pGroupList[i].wFlags |= pGroupInfo->wFlags & UF_DISABLED;
676 }
677
678 // Modify members list
679 g_pGroupList[i].dwNumMembers = pGroupInfo->dwNumMembers;
680 g_pGroupList[i].pMembers = (DWORD *)realloc(g_pGroupList[i].pMembers, sizeof(DWORD) * g_pGroupList[i].dwNumMembers);
681 memcpy(g_pGroupList[i].pMembers, pGroupInfo->pMembers, sizeof(DWORD) * g_pGroupList[i].dwNumMembers);
682
683 // Mark group record as modified and notify clients
684 g_pGroupList[i].wFlags |= UF_MODIFIED;
685 SendUserDBUpdate(USER_DB_MODIFY, g_pGroupList[i].dwId, NULL, &g_pGroupList[i]);
686 dwResult = RCC_SUCCESS;
687 break;
688 }
689
690 MutexUnlock(m_hMutexGroupAccess);
691 return dwResult;
692 }
693
694
695 //
696 // Set user's password
697 //
698
699 DWORD SetUserPassword(DWORD dwId, BYTE *pszPassword, BOOL bResetChPasswd)
700 {
701 DWORD i, dwResult = RCC_INVALID_USER_ID;
702
703 MutexLock(m_hMutexUserAccess, INFINITE);
704
705 // Find user
706 for(i = 0; i < g_dwNumUsers; i++)
707 if (g_pUserList[i].dwId == dwId)
708 {
709 memcpy(g_pUserList[i].szPassword, pszPassword, SHA1_DIGEST_SIZE);
710 g_pUserList[i].nGraceLogins = MAX_GRACE_LOGINS;
711 g_pUserList[i].wFlags |= UF_MODIFIED;
712 if (bResetChPasswd)
713 g_pUserList[i].wFlags &= ~UF_CHANGE_PASSWORD;
714 dwResult = RCC_SUCCESS;
715 break;
716 }
717
718 MutexUnlock(m_hMutexUserAccess);
719 return dwResult;
720 }