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