1 karl 1.21 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.16 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 karl 1.12 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.16 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.19 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.21 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.2 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
15 kumpf 1.4 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
18 mike 1.2 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
|
20 karl 1.21 //
|
21 kumpf 1.4 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
22 mike 1.2 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
24 kumpf 1.4 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
27 mike 1.2 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
|
30 kumpf 1.4 //==============================================================================
|
31 mike 1.2 //
32 //%////////////////////////////////////////////////////////////////////////////
33
34
35 ///////////////////////////////////////////////////////////////////////////////
|
36 david.dillard 1.20 //
37 // This file implements the functionality required to manage password file.
|
38 mike 1.2 //
39 ///////////////////////////////////////////////////////////////////////////////
40
41 #include <Pegasus/Common/FileSystem.h>
42 #include <Pegasus/Common/Logger.h>
43 #include <Pegasus/Common/System.h>
44 #include <Pegasus/Common/Tracer.h>
|
45 mike 1.22 #include <Pegasus/Common/IPCExceptions.h>
|
46 mike 1.2
|
47 kumpf 1.3 #include <Pegasus/Config/ConfigManager.h>
48
|
49 mike 1.2 #include <Pegasus/Security/UserManager/UserFileHandler.h>
50 #include <Pegasus/Security/UserManager/UserExceptions.h>
|
51 kumpf 1.23 #include <Pegasus/Common/MessageLoader.h>
|
52 mike 1.2
53 PEGASUS_USING_STD;
54
55 PEGASUS_NAMESPACE_BEGIN
56
|
57 david.dillard 1.20 const unsigned char UserFileHandler::_SALT_STRING[] =
|
58 kumpf 1.23 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
59 mike 1.2
|
60 david.dillard 1.20 const String UserFileHandler::_PROPERTY_NAME_PASSWORD_FILEPATH =
|
61 kumpf 1.23 "passwordFilePath";
|
62 kumpf 1.3
63 // Initialize the mutex timeout to 5000 ms.
64 const Uint32 UserFileHandler::_MUTEX_TIMEOUT = 5000;
65
|
66 mike 1.2 //
67 // Generate random salt key for password encryption refer to crypt(3C)
68 //
69 void UserFileHandler::_GetSalt(char *salt)
70 {
|
71 kumpf 1.23 long randNum;
72 Uint32 sec;
73 Uint32 milliSec;
|
74 mike 1.2
|
75 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "PasswordFile::_GetSalt");
|
76 mike 1.2
77 //
|
78 david.dillard 1.20 // Generate a random number and get the salt
|
79 mike 1.2 //
|
80 kumpf 1.23 System::getCurrentTime(sec, milliSec);
|
81 mike 1.2
|
82 kumpf 1.23 srand((int) sec);
|
83 keith.petley 1.10 #ifdef PEGASUS_PLATFORM_SOLARIS_SPARC
|
84 kumpf 1.23 Unit32 seed;
|
85 keith.petley 1.10 randNum = rand_r(*seed);
86 #else
|
87 mike 1.2 randNum = rand();
|
88 keith.petley 1.10 #endif
|
89 mike 1.2
90 //
|
91 david.dillard 1.20 // Make sure the random number generated is between 0-63.
|
92 mike 1.2 // refer to _SALT_STRING variable
93 //
94 *salt++ = _SALT_STRING[ randNum & 0x3f ];
95 randNum >>= 6;
96 *salt++ = _SALT_STRING[ randNum & 0x3f ];
97
|
98 kumpf 1.23 *salt = '\0';
|
99 mike 1.2
|
100 kumpf 1.5 PEG_METHOD_EXIT();
|
101 mike 1.2 }
102
103 //
|
104 david.dillard 1.20 // Constructor.
|
105 mike 1.2 //
106 UserFileHandler::UserFileHandler()
107 {
|
108 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "UserFileHandler::UserFileHandler");
|
109 mike 1.2
|
110 kumpf 1.3 //
111 // Get an instance of the ConfigManager.
112 //
|
113 joyce.j 1.18 ConfigManager* configManager;
114 configManager = ConfigManager::getInstance();
|
115 mike 1.2
|
116 kumpf 1.3 //
117 // Get the PasswordFilePath property from the Config Manager.
118 //
119 String passwdFile;
|
120 kumpf 1.15 passwdFile = ConfigManager::getHomedPath(
121 configManager->getCurrentValue(_PROPERTY_NAME_PASSWORD_FILEPATH));
|
122 mike 1.2
|
123 kumpf 1.3 //
124 // Construct a PasswordFile object.
125 //
|
126 a.arora 1.14 _passwordFile.reset(new PasswordFile(passwdFile));
|
127 mike 1.2
128 //
|
129 kumpf 1.3 // Load the user information in to the cache.
|
130 mike 1.2 //
|
131 kumpf 1.24 _loadAllUsers();
|
132 mike 1.2
|
133 kumpf 1.3 //
134 // Initialize the mutex, mutex lock needs to be held for any updates
135 // to the password cache and password file.
136 //
|
137 a.arora 1.14 _mutex.reset(new Mutex);
|
138 kumpf 1.3
|
139 kumpf 1.5 PEG_METHOD_EXIT();
|
140 mike 1.2 }
141
142
143 //
|
144 david.dillard 1.20 // Destructor.
|
145 mike 1.2 //
146 UserFileHandler::~UserFileHandler()
147 {
|
148 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "UserFileHandler::~UserFileHandler");
|
149 mike 1.2
|
150 kumpf 1.5 PEG_METHOD_EXIT();
|
151 mike 1.2 }
152
|
153 david.dillard 1.20 //
|
154 mike 1.2 // Load all user names and password
155 //
156 void UserFileHandler::_loadAllUsers ()
157 {
|
158 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "UserFileHandler::_loadAllUsers");
|
159 mike 1.2
160 try
161 {
162 _passwordTable.clear();
163 _passwordFile->load(_passwordTable);
164 }
|
165 kumpf 1.13 catch (CannotOpenFile&)
|
166 mike 1.2 {
167 _passwordTable.clear();
|
168 kumpf 1.5 PEG_METHOD_EXIT();
|
169 kumpf 1.13 throw;
|
170 mike 1.2 }
|
171 kumpf 1.5 PEG_METHOD_EXIT();
|
172 mike 1.2 }
173
|
174 kumpf 1.3 void UserFileHandler::_Update(
|
175 kumpf 1.23 char operation,
176 const String& userName,
177 const String& password)
|
178 kumpf 1.3 {
|
179 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "UserFileHandler::_Update");
|
180 kumpf 1.3
181 //
182 // Hold the mutex lock.
183 // This will allow any one of the update operations to be performed
184 // at any given time
185 //
186
187 try
188 {
|
189 kumpf 1.28 if (!_mutex->timed_lock(_MUTEX_TIMEOUT))
190 {
191 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
192 MessageLoaderParms(
193 "Security.UserManager.UserFileHandler.TIMEOUT",
194 "Timed out while attempting to perform the requested "
195 "operation. Try the operation again."));
196 }
|
197 kumpf 1.3 }
|
198 kumpf 1.13 catch (WaitFailed&)
|
199 kumpf 1.3 {
|
200 kumpf 1.28 // ATTN: This is an error case, not a timeout scenario
|
201 kumpf 1.23 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
202 MessageLoaderParms(
203 "Security.UserManager.UserFileHandler.TIMEOUT",
204 "Timed out while attempting to perform the requested "
205 "operation. Try the operation again."));
|
206 kumpf 1.3 }
207
208 switch (operation)
209 {
|
210 kumpf 1.23 case ADD_USER:
|
211 kumpf 1.3 if (!_passwordTable.insert(userName,password))
212 {
213 _mutex->unlock();
|
214 kumpf 1.5 PEG_METHOD_EXIT();
|
215 kumpf 1.3 throw PasswordCacheError();
216 }
|
217 kumpf 1.23 break;
|
218 kumpf 1.3
|
219 kumpf 1.23 case MODIFY_USER:
|
220 kumpf 1.3 if (!_passwordTable.remove(userName))
221 {
222 _mutex->unlock();
|
223 kumpf 1.5 PEG_METHOD_EXIT();
|
224 kumpf 1.3 throw PasswordCacheError();
225 }
226 if (!_passwordTable.insert(userName,password))
227 {
228 _mutex->unlock();
|
229 kumpf 1.23 Logger::put_l(
230 Logger::ERROR_LOG, System::CIMSERVER, Logger::SEVERE,
|
231 kumpf 1.27 MessageLoaderParms(
232 "Security.UserManager.UserFileHandler."
233 "ERROR_UPDATING_USER_INFO",
234 "Error updating the user information for user $0.",
235 userName));
|
236 kumpf 1.5 PEG_METHOD_EXIT();
|
237 kumpf 1.3 throw PasswordCacheError();
238 }
|
239 kumpf 1.23 break;
|
240 kumpf 1.3
|
241 kumpf 1.23 case REMOVE_USER:
|
242 kumpf 1.3
243 //Remove the existing user name and password from the table
244 if (!_passwordTable.remove(userName))
245 {
246 _mutex->unlock();
|
247 kumpf 1.5 PEG_METHOD_EXIT();
|
248 kumpf 1.3 throw InvalidUser(userName);
249 }
|
250 kumpf 1.23 break;
|
251 david.dillard 1.20
|
252 kumpf 1.23 default:
253 // Should never get here
254 break;
|
255 kumpf 1.3 }
|
256 david.dillard 1.20
|
257 kumpf 1.3 // Store the entry in the password file
258 try
259 {
260 _passwordFile->save(_passwordTable);
261 }
|
262 david.dillard 1.20 catch (const CannotOpenFile&)
|
263 kumpf 1.3 {
264 _mutex->unlock();
|
265 kumpf 1.5 PEG_METHOD_EXIT();
|
266 david.dillard 1.20 throw;
|
267 kumpf 1.3 }
|
268 david.dillard 1.20 catch (const CannotRenameFile&)
|
269 kumpf 1.3 {
270 //
271 // reload password hash table from file
272 //
273 _loadAllUsers();
274
275 _mutex->unlock();
|
276 kumpf 1.5 PEG_METHOD_EXIT();
|
277 david.dillard 1.20 throw;
|
278 kumpf 1.3 }
279 _mutex->unlock();
|
280 kumpf 1.5 PEG_METHOD_EXIT();
|
281 kumpf 1.3 }
282
283
|
284 david.dillard 1.20 //
|
285 mike 1.2 // Add user entry to file
|
286 david.dillard 1.20 //
|
287 mike 1.2 void UserFileHandler::addUserEntry(
|
288 kumpf 1.23 const String& userName,
289 const String& password)
|
290 mike 1.2 {
|
291 kumpf 1.23 char salt[3];
292 String encryptedPassword;
|
293 mike 1.2
|
294 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "UserFileHandler::addUserEntry");
|
295 mike 1.2
296 // Check if the user already exists
297 if (_passwordTable.contains(userName))
298 {
|
299 kumpf 1.5 PEG_METHOD_EXIT();
|
300 kumpf 1.23 throw DuplicateUser(userName);
|
301 mike 1.2 }
302
303 // encrypt password
304 _GetSalt(salt);
305
|
306 kumpf 1.7 encryptedPassword = System::encryptPassword(password.getCString(),salt);
|
307 mike 1.2
|
308 kumpf 1.3 // add the user to the cache and password file
309 _Update(ADD_USER,userName, encryptedPassword);
|
310 mike 1.2
|
311 kumpf 1.5 PEG_METHOD_EXIT();
|
312 mike 1.2 }
313
|
314 david.dillard 1.20 //
315 // Modify user entry in file
|
316 mike 1.2 //
317 void UserFileHandler::modifyUserEntry(
|
318 kumpf 1.23 const String& userName,
319 const String& password,
320 const String& newPassword)
|
321 mike 1.2 {
|
322 kumpf 1.23 char salt[3];
323 String encryptedPassword;
|
324 mike 1.2
|
325 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "UserFileHandler::modifyUserEntry");
|
326 mike 1.2
327 //
328 // Check if the given password matches the passwd in the file
329 //
|
330 kumpf 1.24 if (!verifyCIMUserPassword(userName,password))
|
331 mike 1.2 {
|
332 kumpf 1.5 PEG_METHOD_EXIT();
|
333 kumpf 1.24 throw PasswordMismatch(userName);
|
334 mike 1.2 }
335
336 // encrypt new password
337 _GetSalt(salt);
338
|
339 kumpf 1.7 encryptedPassword = System::encryptPassword(newPassword.getCString(),salt);
|
340 mike 1.2
|
341 kumpf 1.3 _Update(MODIFY_USER, userName, encryptedPassword);
|
342 mike 1.2
|
343 kumpf 1.5 PEG_METHOD_EXIT();
|
344 mike 1.2 }
345
|
346 david.dillard 1.20 //
347 // Remove user entry from file
348 //
|
349 mike 1.2 void UserFileHandler::removeUserEntry(const String& userName)
350 {
|
351 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "UserFileHandler::removeUserEntry");
|
352 mike 1.2
|
353 kumpf 1.3 _Update(REMOVE_USER, userName);
|
354 mike 1.2
|
355 kumpf 1.5 PEG_METHOD_EXIT();
|
356 mike 1.2 }
357
358 //
359 // Get a list of all the user names.
360 //
361 void UserFileHandler::getAllUserNames(Array<String>& userNames)
362 {
|
363 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "UserFileHandler::getAllUserNames");
|
364 mike 1.2
365 userNames.clear();
366
367 for (PasswordTable::Iterator i = _passwordTable.start(); i; i++)
368 {
369 userNames.append(i.key());
370 }
|
371 kumpf 1.5 PEG_METHOD_EXIT();
|
372 mike 1.2 }
373
374 //
375 // Verify whether the specified CIM user is valid
376 //
377 Boolean UserFileHandler::verifyCIMUser (const String& userName)
378 {
|
379 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER, "UserFileHandler::verifyCIMUser");
|
380 mike 1.2
|
381 kumpf 1.5 PEG_METHOD_EXIT();
|
382 mike 1.2 return _passwordTable.contains(userName);
383 }
384
385 //
386 // Verify whether the specified user's password is valid
387 //
|
388 kumpf 1.23 Boolean UserFileHandler::verifyCIMUserPassword(
389 const String& userName,
390 const String& password)
|
391 mike 1.2 {
|
392 kumpf 1.5 PEG_METHOD_ENTER(TRC_USER_MANAGER,
|
393 kumpf 1.23 "UserFileHandler::verifyCIMUserPassword");
|
394 mike 1.2
395 // Check if the user's password mathches the specified password
|
396 kumpf 1.23 String curPassword;
397 String encryptedPassword;
398 String saltStr;
|
399 mike 1.2
400 // Check if the user exists in the password table
401 if ( !_passwordTable.lookup(userName,curPassword) )
402 {
|
403 kumpf 1.5 PEG_METHOD_EXIT();
|
404 mike 1.2 throw InvalidUser(userName);
405 }
406
407 saltStr = curPassword.subString(0,2);
408
409 encryptedPassword =
|
410 kumpf 1.7 System::encryptPassword(password.getCString(),saltStr.getCString());
|
411 mike 1.2
|
412 venkat.puvvada 1.26 if ( curPassword != encryptedPassword )
|
413 mike 1.2 {
|
414 kumpf 1.5 PEG_METHOD_EXIT();
|
415 mike 1.2 return false;
416 }
417
|
418 kumpf 1.5 PEG_METHOD_EXIT();
|
419 mike 1.2 return true;
420 }
421 PEGASUS_NAMESPACE_END
422
423
|