]> git.saurik.com Git - apple/security.git/blame - cdsa/mds/MDSSession.cpp
Security-177.tar.gz
[apple/security.git] / cdsa / mds / MDSSession.cpp
CommitLineData
bac41a7b
A
1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19#include "MDSSession.h"
20
21#include <Security/DbContext.h>
22#include "MDSModule.h"
29654253
A
23#include "MDSAttrParser.h"
24#include "MDSAttrUtils.h"
bac41a7b
A
25
26#include <memory>
27#include <Security/cssmerr.h>
28#include <Security/utilities.h>
29#include <Security/logging.h>
29654253
A
30#include <Security/debugging.h>
31#include <Security/mds_schema.h>
bac41a7b
A
32
33#include <sys/types.h>
29654253 34#include <sys/param.h>
bac41a7b
A
35#include <dirent.h>
36#include <fcntl.h>
29654253 37#include <assert.h>
bac41a7b
A
38#include <time.h>
39
29654253
A
40/*
41 * The layout of the various MDS DB files on disk is as follows:
42 *
43 * /var/tmp/mds -- owner = root, mode = 01777, world writable, sticky
44 * mdsObject.db -- owner = root, mode = 0644, object DB
45 * mdsDirectory.db -- owner = root, mode = 0644, MDS directory DB
46 * mds.lock -- temporary, owner = root, protects creation of
47 * previous two files
48 * <uid>/ -- owner = <uid>, mode = 0644
49 * mdsObject.db -- owner = <uid>, mode = 0644, object DB
50 * mdsDirectory.db -- owner = <uid>, mode = 0644, MDS directory DB
51 * mds.lock -- temporary, owner = <uid>, protects creation of
52 * previous two files
53 *
54 * The /var/tmp/mds directory and the two db files in it are created by root
55 * via SS or an AEWP call. Each user except for root has their own private
56 * directory with two DB files and a lock. The first time a user accesses MDS,
57 * the per-user directory is created and the per-user DB files are created as
58 * copies of the system DB files. Fcntl() with a F_RDLCK is used to lock the system
59 * DB files when they are the source of these copies; this is the same mechanism
60 * used by the underlying AtomincFile.
61 *
62 * The sticky bit in /var/tmp/mds ensures that users cannot delete, rename, and/or
63 * replace the root-owned DB files in that directory, and that users can not
64 * modify other user's private MDS directories.
65 */
66namespace Security
67{
bac41a7b 68
29654253
A
69/*
70 * Nominal location of Security.framework.
71 */
72#define MDS_SYSTEM_PATH "/System/Library/Frameworks"
73#define MDS_SYSTEM_FRAME "Security.framework"
bac41a7b 74
29654253
A
75/*
76 * Nominal location of standard plugins.
77 */
78#define MDS_BUNDLE_PATH "/System/Library/Security"
79#define MDS_BUNDLE_EXTEN ".bundle"
bac41a7b 80
bac41a7b 81
29654253
A
82/*
83 * Location of system MDS database and lock files.
84 */
85#define MDS_SYSTEM_DB_DIR "/private/var/tmp/mds"
86#define MDS_LOCK_FILE_NAME "mds.lock"
87#define MDS_OBJECT_DB_NAME "mdsObject.db"
88#define MDS_DIRECT_DB_NAME "mdsDirectory.db"
89#define MDS_LOCK_FILE_PATH MDS_SYSTEM_DB_DIR "/" MDS_LOCK_FILE_NAME
90#define MDS_OBJECT_DB_PATH MDS_SYSTEM_DB_DIR "/" MDS_OBJECT_DB_NAME
91#define MDS_DIRECT_DB_PATH MDS_SYSTEM_DB_DIR "/" MDS_DIRECT_DB_NAME
bac41a7b 92
29654253
A
93/*
94 * Location of per-user bundles, relative to home directory.
95 * PEr-user DB files are in MDS_SYSTEM_DB_DIR/<uid>/.
96 */
97#define MDS_USER_DB_DIR "Library/Security"
98#define MDS_USER_BUNDLE "Library/Security"
99
100/* time to wait in ms trying to acquire lock */
101#define DB_LOCK_TIMEOUT (2 * 1000)
102
103/* Minimum interval, in seconds, between rescans for plugin changes */
104#define MDS_SCAN_INTERVAL 10
105
106/* initial debug - start from scratch each time */
107#define START_FROM_SCRATCH 0
108
109/* debug - skip file-level locking */
110#define SKIP_FILE_LOCKING 0
111
df0e469f
A
112#ifndef NDEBUG
113
29654253
A
114/* Only allow root to create and update system DB files - in the final config this
115 * will be true */
116#define SYSTEM_MDS_ROOT_ONLY 0
117
118/*
119 * Early development; no Security Server/root involvement with system DB creation.
120 * If this is true, SYSTEM_MDS_ROOT_ONLY must be false (though both can be
121 * false for intermediate testing).
122 */
123#define SYSTEM_DBS_VIA_USER 1
bac41a7b 124
df0e469f
A
125#else /* NDEBUG */
126/* normal deployment case */
127#define SYSTEM_MDS_ROOT_ONLY 1
128#define SYSTEM_DBS_VIA_USER 0
129#endif /* NDEBUG */
bac41a7b 130
29654253
A
131/*
132 * Determine if both of the specified DB files exist as
133 * accessible regular files. Returns true if they do. If the purge argument
134 * is true, we'll ensure that either both or neither of the files exist on
135 * exit.
136 */
137static bool doFilesExist(
138 const char *objDbFile,
139 const char *directDbFile,
140 bool purge) // false means "passive" check
bac41a7b 141{
29654253
A
142 struct stat sb;
143 bool objectExist = false;
144 bool directExist = false;
145
146 if (stat(objDbFile, &sb) == 0) {
147 /* Object DB exists */
148 if(!(sb.st_mode & S_IFREG)) {
149 MSDebug("deleting non-regular file %s", objDbFile);
150 if(purge && unlink(objDbFile)) {
151 MSDebug("unlink(%s) returned %d", objDbFile, errno);
152 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
153 }
154 }
155 else {
156 objectExist = true;
157 }
158 }
159 if (stat(directDbFile, &sb) == 0) {
160 /* directory DB exists */
161 if(!(sb.st_mode & S_IFREG)) {
162 MSDebug("deleting non-regular file %s", directDbFile);
163 if(purge & unlink(directDbFile)) {
164 MSDebug("unlink(%s) returned %d", directDbFile, errno);
165 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
166 }
167 }
168 directExist = true;
169 }
170 if(objectExist && directExist) {
171 /* both databases exist as regular files */
172 return true;
173 }
174 else if(!purge) {
175 return false;
176 }
177
178 /* at least one does not exist - ensure neither of them do */
179 if(objectExist) {
180 if(unlink(objDbFile)) {
181 MSDebug("unlink(%s) returned %d", objDbFile, errno);
182 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
183 }
184 }
185 if(directExist) {
186 if(unlink(directDbFile)) {
187 MSDebug("unlink(%s) returned %d", directDbFile, errno);
188 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
189 }
190 }
191 return false;
bac41a7b
A
192}
193
29654253
A
194/*
195 * Determine if specified directory exists.
196 */
197static bool doesDirectExist(
198 const char *dirPath)
199{
200 struct stat sb;
201
202 if (stat(dirPath, &sb)) {
203 return false;
204 }
205 if(!(sb.st_mode & S_IFDIR)) {
206 return false;
207 }
208 return true;
209}
bac41a7b 210
29654253
A
211/*
212 * Create specified directory if it doesn't already exist.
213 * Zero for mode means "use the default provided by 0755 modified by umask".
214 */
215static int createDir(
216 const char *dirPath,
217 mode_t dirMode = 0)
218{
219 if(doesDirectExist(dirPath)) {
220 return 0;
221 }
222 int rtn = mkdir(dirPath, 0755);
223 if(rtn) {
224 if(errno == EEXIST) {
225 /* this one's OK */
226 rtn = 0;
227 }
228 else {
229 rtn = errno;
230 MSDebug("mkdir(%s) returned %d", dirPath, errno);
231 }
232 }
233 if((rtn == 0) && (dirMode != 0)) {
234 rtn = chmod(dirPath, dirMode);
235 if(rtn) {
236 MSDebug("chmod(%s) returned %d", dirPath, errno);
237 }
238 }
239 return rtn;
240}
241
242/*
243 * Create an MDS session.
244 */
bac41a7b
A
245MDSSession::MDSSession (const Guid *inCallerGuid,
246 const CSSM_MEMORY_FUNCS &inMemoryFunctions) :
29654253
A
247 DatabaseSession(MDSModule::get().databaseManager()),
248 mCssmMemoryFunctions (inMemoryFunctions),
249 mModule(MDSModule::get()),
bac41a7b
A
250 mLockFd(-1)
251{
29654253 252 MSDebug("MDSSession::MDSSession");
bac41a7b 253
29654253
A
254 #if START_FROM_SCRATCH
255 unlink(MDS_LOCK_FILE_PATH);
256 unlink(MDS_OBJECT_DB_PATH);
257 unlink(MDS_DIRECT_DB_PATH);
258 #endif
259
bac41a7b
A
260 mCallerGuidPresent = inCallerGuid != nil;
261 if (mCallerGuidPresent)
262 mCallerGuid = *inCallerGuid;
bac41a7b 263
29654253
A
264 /*
265 * Create DB files if necessary; make sure they are up-to-date
266 */
267 // no! done in either install or open! updateDataBases();
bac41a7b
A
268}
269
270MDSSession::~MDSSession ()
271{
29654253
A
272 MSDebug("MDSSession::~MDSSession");
273 releaseLock(mLockFd);
bac41a7b
A
274}
275
276void
277MDSSession::terminate ()
278{
29654253
A
279 MSDebug("MDSSession::terminate");
280 releaseLock(mLockFd);
bac41a7b
A
281 closeAll();
282}
283
29654253
A
284/*
285 * Called by security server or AEWP-executed privileged tool.
286 */
bac41a7b
A
287void
288MDSSession::install ()
289{
29654253
A
290 if((getuid() != (uid_t)0) && SYSTEM_MDS_ROOT_ONLY) {
291 CssmError::throwMe(CSSMERR_DL_OS_ACCESS_DENIED);
292 }
293
294 int sysFdLock = -1;
295 try {
296 /* before we obtain the lock, ensure the the system MDS DB directory exists */
297 if(createDir(MDS_SYSTEM_DB_DIR, 01777)) {
298 MSDebug("Error creating system MDS dir; aborting.");
299 CssmError::throwMe(CSSMERR_DL_OS_ACCESS_DENIED);
300 }
301
302 if(!obtainLock(MDS_LOCK_FILE_PATH, sysFdLock, DB_LOCK_TIMEOUT)) {
303 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
304 }
305 if(!systemDatabasesPresent(true)) {
df0e469f
A
306 /*
307 * Root umask is 0 when this runs, so specify readable (only)
308 * by world. Also, turn off autocommit during initial
309 * system DB population.
310 */
311 bool created = createSystemDatabases(CSSM_FALSE, 0644);
29654253
A
312 if(created) {
313 /*
314 * Skip possible race condition in which this is called twice,
315 * both via SS by user procs who say "no system DBs present"
316 * in their updateDataBases() method.
317 *
318 * Do initial population of system DBs.
319 */
320 DbFilesInfo dbFiles(*this, MDS_SYSTEM_DB_DIR);
29654253 321 dbFiles.autoCommit(CSSM_FALSE);
29654253
A
322 dbFiles.updateSystemDbInfo(MDS_SYSTEM_PATH, MDS_BUNDLE_PATH);
323 }
324 }
325 }
326 catch(...) {
327 if(sysFdLock != -1) {
328 releaseLock(sysFdLock);
329 }
330 throw;
331 }
332 releaseLock(sysFdLock);
bac41a7b
A
333}
334
335//
336// In this implementation, the uninstall() call is not supported since
337// we do not allow programmatic deletion of the MDS databases.
338//
339
340void
341MDSSession::uninstall ()
342{
343 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
344}
345
29654253
A
346/*
347 * Common private open routine given a full specified path.
348 *
349 * FIXME: both of these dbOpen routines leak like crazy even though
350 * we know we close properly.
351 * Typical stack trace (from MallocDebug) of a leak is
352 *
353 * DatabaseSession::DbOpen(char const *, cssm_net_address const...)
354 * DatabaseManager::dbOpen(Security::DatabaseSession &, ...)
355 * Database::_dbOpen(Security::DatabaseSession &, unsigned long, ...)
356 * AppleDatabase::dbOpen(Security::DbContext &)
357 * DbModifier::openDatabase(void)
358 * DbModifier::getDbVersion(void)
359 * DbVersion::DbVersion(Security::AtomicFile &, ...)
360 * DbVersion::open(void)
361 * MetaRecord::unpackRecord(Security::ReadSection const &, ...)
362 * MetaRecord::unpackAttribute(Security::ReadSection const &, ...)
363 * MetaAttribute::unpackAttribute(Security::ReadSection const &, ..)
364 * TypedMetaAttribute<Security::StringValue>::unpackValue(...)
365 * TrackingAllocator::malloc(unsigned long)
366 */
367CSSM_DB_HANDLE MDSSession::dbOpen(
368 const char *dbName)
bac41a7b 369{
29654253
A
370 MSDebug("Opening %s", dbName);
371 CSSM_DB_HANDLE dbHand;
372 DatabaseSession::DbOpen(dbName,
373 NULL, // DbLocation
374 CSSM_DB_ACCESS_READ,
375 NULL, // AccessCred - hopefully optional
376 NULL, // OpenParameters
377 dbHand);
378 return dbHand;
bac41a7b
A
379}
380
29654253
A
381
382/* DatabaseSession routines we need to override */
383void MDSSession::DbOpen(const char *DbName,
384 const CSSM_NET_ADDRESS *DbLocation,
385 CSSM_DB_ACCESS_TYPE AccessRequest,
386 const AccessCredentials *AccessCred,
387 const void *OpenParameters,
388 CSSM_DB_HANDLE &DbHandle)
bac41a7b 389{
29654253
A
390 /* make sure DBs are up-to-date */
391 updateDataBases();
392
393 /*
394 * Only task here is map incoming DbName - specified in the CDSA
395 * spec - to a filename we actually use (which is a path to either
396 * a system MDS DB file or a per-user MDS DB file).
397 */
398 if(DbName == NULL) {
399 CssmError::throwMe(CSSMERR_DL_INVALID_DB_NAME);
400 }
401 const char *dbName;
402 if(!strcmp(DbName, MDS_OBJECT_DIRECTORY_NAME)) {
403 dbName = MDS_OBJECT_DB_NAME;
404 }
405 else if(!strcmp(DbName, MDS_CDSA_DIRECTORY_NAME)) {
406 dbName = MDS_DIRECT_DB_NAME;
407 }
408 else {
409 CssmError::throwMe(CSSMERR_DL_INVALID_DB_NAME);
410 }
411 char fullPath[MAXPATHLEN];
412 dbFullPath(dbName, fullPath);
413 DatabaseSession::DbOpen(fullPath, DbLocation, AccessRequest, AccessCred,
414 OpenParameters, DbHandle);
bac41a7b
A
415}
416
29654253
A
417void
418MDSSession::GetDbNames(CSSM_NAME_LIST_PTR &outNameList)
bac41a7b 419{
29654253
A
420 outNameList = new CSSM_NAME_LIST[1];
421 outNameList->NumStrings = 2;
422 outNameList->String = new (char *)[2];
423 outNameList->String[0] = MDSCopyCstring(MDS_OBJECT_DIRECTORY_NAME);
424 outNameList->String[1] = MDSCopyCstring(MDS_CDSA_DIRECTORY_NAME);
bac41a7b
A
425}
426
29654253
A
427void
428MDSSession::FreeNameList(CSSM_NAME_LIST &inNameList)
bac41a7b 429{
29654253
A
430 delete [] inNameList.String[0];
431 delete [] inNameList.String[1];
432 delete [] inNameList.String;
bac41a7b
A
433}
434
29654253
A
435void MDSSession::GetDbNameFromHandle(CSSM_DB_HANDLE DBHandle,
436 char **DbName)
bac41a7b 437{
29654253
A
438 printf("GetDbNameFromHandle: code on demand\n");
439 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
440}
bac41a7b
A
441
442//
443// Attempt to obtain an exclusive lock over the the MDS databases. The
444// parameter is the maximum amount of time, in milliseconds, to spend
445// trying to obtain the lock. A value of zero means to return failure
446// right away if the lock cannot be obtained.
447//
bac41a7b 448bool
29654253
A
449MDSSession::obtainLock(
450 const char *lockFile, // e.g. MDS_LOCK_FILE_PATH
451 int &fd, // IN/OUT
452 int timeout) // default 0
bac41a7b 453{
29654253
A
454 #if SKIP_FILE_LOCKING
455 return true;
456 #else
457
bac41a7b
A
458 static const int kRetryDelay = 250; // ms
459
29654253
A
460 fd = open(MDS_LOCK_FILE_PATH, O_CREAT | O_EXCL, 0544);
461 while (fd == -1 && timeout >= kRetryDelay) {
bac41a7b
A
462 timeout -= kRetryDelay;
463 usleep(1000 * kRetryDelay);
29654253 464 mLockFd = open(MDS_LOCK_FILE_PATH, O_CREAT | O_EXCL, 0544);
bac41a7b
A
465 }
466
29654253
A
467 return (fd != -1);
468 #endif /* SKIP_FILE_LOCKING */
bac41a7b
A
469}
470
471//
472// Release the exclusive lock over the MDS databases. If this session
473// does not hold the lock, this method does nothing.
474//
475
476void
29654253 477MDSSession::releaseLock(int &fd)
bac41a7b 478{
29654253
A
479 #if !SKIP_FILE_LOCKING
480 if (fd != -1) {
481 close(fd);
482 unlink(MDS_LOCK_FILE_PATH);
483 fd = -1;
bac41a7b 484 }
29654253 485 #endif
bac41a7b
A
486}
487
29654253
A
488/* given DB file name, fill in fully specified path */
489void MDSSession::dbFullPath(
490 const char *dbName,
491 char fullPath[MAXPATHLEN+1])
492{
493 mModule.getDbPath(fullPath);
494 assert(fullPath[0] != '\0');
495 strcat(fullPath, "/");
496 strcat(fullPath, dbName);
497}
bac41a7b 498
29654253
A
499/*
500 * See if any per-user bundles exist in specified directory. Returns true if so.
501 * First the check for one entry....
502 */
503static bool isBundle(
504 const struct dirent *dp)
505{
506 if(dp == NULL) {
507 return false;
508 }
509 /* NFS directories show up as DT_UNKNOWN */
510 switch(dp->d_type) {
511 case DT_UNKNOWN:
512 case DT_DIR:
513 break;
514 default:
515 return false;
516 }
517 int suffixLen = strlen(MDS_BUNDLE_EXTEN);
518 int len = strlen(dp->d_name);
519
520 return (len >= suffixLen) &&
521 !strcmp(dp->d_name + len - suffixLen, MDS_BUNDLE_EXTEN);
522}
523
524/* now the full directory search */
525static bool checkUserBundles(
526 const char *bundlePath)
bac41a7b 527{
29654253
A
528 MSDebug("searching for user bundles in %s", bundlePath);
529 DIR *dir = opendir(bundlePath);
530 if (dir == NULL) {
531 return false;
532 }
533 struct dirent *dp;
534 bool rtn = false;
535 while ((dp = readdir(dir)) != NULL) {
536 if(isBundle(dp)) {
537 /* any other checking to do? */
538 rtn = true;
539 break;
540 }
541 }
542 closedir(dir);
543 MSDebug("...%s bundle(s) found", rtn ? "" : "No");
544 return rtn;
545}
546
547#define COPY_BUF_SIZE 1024
548
549/* Single file copy with locking */
550static void safeCopyFile(
551 const char *fromPath,
552 const char *toPath)
553{
554 /* open source for reading */
555 int srcFd = open(fromPath, O_RDONLY, 0);
556 if(srcFd < 0) {
557 /* FIXME - what error would we see if the file is locked for writing
558 * by someone else? We definitely have to handle that. */
559 int error = errno;
560 MSDebug("Error %d opening system DB file %s\n", error, fromPath);
561 UnixError::throwMe(error);
562 }
bac41a7b 563
29654253
A
564 /* acquire the same kind of lock AtomicFile uses */
565 struct flock fl;
566 fl.l_start = 0;
567 fl.l_len = 1;
568 fl.l_pid = getpid();
569 fl.l_type = F_RDLCK; // AtomicFile gets F_WRLCK
570 fl.l_whence = SEEK_SET;
571
572 // Keep trying to obtain the lock if we get interupted.
573 for (;;) {
574 if (::fcntl(srcFd, F_SETLKW, reinterpret_cast<int>(&fl)) == -1) {
575 int error = errno;
576 if (error == EINTR) {
577 continue;
578 }
579 MSDebug("Error %d locking system DB file %s\n", error, fromPath);
580 UnixError::throwMe(error);
581 }
582 else {
583 break;
584 }
585 }
586
587 /* create destination */
588 int destFd = open(toPath, O_WRONLY | O_APPEND | O_CREAT | O_TRUNC | O_EXCL, 0644);
589 if(destFd < 0) {
590 int error = errno;
591 MSDebug("Error %d opening user DB file %s\n", error, toPath);
592 UnixError::throwMe(error);
593 }
bac41a7b 594
29654253
A
595 /* copy */
596 char buf[COPY_BUF_SIZE];
597 while(1) {
598 int bytesRead = read(srcFd, buf, COPY_BUF_SIZE);
599 if(bytesRead == 0) {
600 break;
601 }
602 if(bytesRead < 0) {
603 int error = errno;
604 MSDebug("Error %d reading system DB file %s\n", error, fromPath);
605 UnixError::throwMe(error);
606 }
607 int bytesWritten = write(destFd, buf, bytesRead);
608 if(bytesWritten < 0) {
609 int error = errno;
610 MSDebug("Error %d writing user DB file %s\n", error, toPath);
611 UnixError::throwMe(error);
612 }
613 }
bac41a7b 614
29654253
A
615 /* unlock source and close both */
616 fl.l_type = F_UNLCK;
617 if (::fcntl(srcFd, F_SETLK, reinterpret_cast<int>(&fl)) == -1) {
618 MSDebug("Error %d unlocking system DB file %s\n", errno, fromPath);
619 }
620 close(srcFd);
621 close(destFd);
622}
623
624/* Copy system DB files to specified user dir. */
625static void copySystemDbs(
626 const char *userDbFileDir)
627{
628 char toPath[MAXPATHLEN+1];
bac41a7b 629
29654253
A
630 sprintf(toPath, "%s/%s", userDbFileDir, MDS_OBJECT_DB_NAME);
631 safeCopyFile(MDS_OBJECT_DB_PATH, toPath);
632 sprintf(toPath, "%s/%s", userDbFileDir, MDS_DIRECT_DB_NAME);
633 safeCopyFile(MDS_DIRECT_DB_PATH, toPath);
634}
635
636/*
637 * Ensure current DB files exist and are up-to-date.
638 * Called from MDSSession constructor and from DataGetFirst, DbOpen, and any
639 * other public functions which access a DB from scratch.
640 */
641void MDSSession::updateDataBases()
642{
643 bool isRoot = (getuid() == (uid_t)0);
644 bool createdSystemDb = false;
bac41a7b 645
29654253
A
646 /*
647 * The first thing we do is to ensure that system DBs are present.
648 * This call right here is the reason for the purge argument in
649 * systemDatabasesPresent(); if we're a user proc, we can't grab the system
650 * MDS lock.
651 */
652 if(!systemDatabasesPresent(false)) {
653 if(isRoot || SYSTEM_DBS_VIA_USER) {
654 /* Either doing actual MDS op as root, or development case:
655 * install as current user */
656 install();
657 }
658 else {
659 /* This path TBD; it involves either a SecurityServer RPC or
660 * a privileged tool exec'd via AEWP. */
661 assert(0);
662 }
663 /* remember this - we have to delete possible existing user DBs */
664 createdSystemDb = true;
665 }
bac41a7b 666
29654253
A
667 /* if we scanned recently, we're done */
668 double delta = mModule.timeSinceLastScan();
669 if(delta < (double)MDS_SCAN_INTERVAL) {
670 return;
bac41a7b 671 }
29654253
A
672
673 /*
674 * Obtain various per-user paths. Root is a special case but follows most
675 * of the same logic from here on.
676 */
677 char userDbFileDir[MAXPATHLEN+1];
678 char userObjDbFilePath[MAXPATHLEN+1];
679 char userDirectDbFilePath[MAXPATHLEN+1];
680 char userBundlePath[MAXPATHLEN+1];
681 char userDbLockPath[MAXPATHLEN+1];
682
683 if(isRoot) {
684 strcat(userDbFileDir, MDS_SYSTEM_DB_DIR);
685 /* no userBundlePath */
686 }
687 else {
688 char *userHome = getenv("HOME");
689 if(userHome == NULL) {
690 /* FIXME - what now, batman? */
691 MSDebug("updateDataBases: no HOME");
692 userHome = "/";
693 }
694 sprintf(userBundlePath, "%s/%s", userHome, MDS_USER_BUNDLE);
695
696 /* DBs go in a per-UID directory in the system MDS DB directory */
697 sprintf(userDbFileDir, "%s/%d", MDS_SYSTEM_DB_DIR, (int)(getuid()));
698 }
699 sprintf(userObjDbFilePath, "%s/%s", userDbFileDir, MDS_OBJECT_DB_NAME);
700 sprintf(userDirectDbFilePath, "%s/%s", userDbFileDir, MDS_DIRECT_DB_NAME);
701 sprintf(userDbLockPath, "%s/%s", userDbFileDir, MDS_LOCK_FILE_NAME);
702
703 /*
704 * Create the per-user directory first...that's where the lock we'll be using
705 * lives. Our createDir() is tolerant of EEXIST errors.
706 */
707 if(!isRoot) {
708 if(createDir(userDbFileDir)) {
709 /* We'll just have to limp along using the read-only system DBs */
710 Syslog::alert("Error creating %s", userDbFileDir);
711 MSDebug("Error creating user DBs; using system DBs");
712 mModule.setDbPath(MDS_SYSTEM_DB_DIR);
713 return;
714 }
715 }
716
717 /* always release mLockFd no matter what happens */
718 if(!obtainLock(userDbLockPath, mLockFd, DB_LOCK_TIMEOUT)) {
719 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
720 }
721 try {
722 if(!isRoot) {
723 if(createdSystemDb) {
724 /* initial creation of system DBs by user - start from scratch */
725 unlink(userObjDbFilePath);
726 unlink(userDirectDbFilePath);
727 }
728
729 /*
730 * System DBs exist and are as up-to-date as we are allowed to make them.
731 * Create per-user DBs if they don't exist.
732 */
733