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