protect_db.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* protect_db.c
  42. * Used to police access to the db. Prevents different instances of
  43. * slapd from clobbering each other
  44. */
  45. #ifndef _WIN32
  46. #define LOCK_FILE "lock"
  47. #define IMPORT_DIR "imports"
  48. #define EXPORT_DIR "exports"
  49. #define SERVER_DIR "server"
  50. #define NUM_TRIES 20
  51. #define WAIT_TIME 250
  52. #include <sys/types.h>
  53. #include <sys/time.h>
  54. #include <sys/stat.h>
  55. #include <fcntl.h> /* open */
  56. #include <unistd.h>
  57. #include <errno.h>
  58. #include <signal.h>
  59. #include <sys/param.h> /* MAXPATHLEN */
  60. #include <dirent.h>
  61. #include <pwd.h>
  62. #endif
  63. #include "protect_db.h"
  64. #include "slap.h"
  65. #ifndef _WIN32
  66. /* This is the unix version of the code to protect the db. */
  67. static int
  68. grab_lockfile()
  69. {
  70. pid_t pid, owning_pid;
  71. char lockfile[MAXPATHLEN];
  72. int fd, x;
  73. int removed_lockfile = 0;
  74. struct timeval t;
  75. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  76. /* Don't use anything that makes a NSPR call here (like LDAPDebug)! This function
  77. gets called by an atexit function, and NSPR is long gone by then. */
  78. /* Get the name of the lockfile */
  79. snprintf(lockfile, sizeof(lockfile), "%s/%s", slapdFrontendConfig->lockdir, LOCK_FILE);
  80. lockfile[sizeof(lockfile)-1] = (char)0;
  81. /* Get our pid */
  82. pid = getpid();
  83. /* Try to grab it */
  84. if ((fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0664)) != -1) {
  85. /* We got the lock, write our pid to the file */
  86. write(fd, (void *) &pid, sizeof(pid_t));
  87. close(fd);
  88. return 0;
  89. }
  90. /* We weren't able to get the lock. Find out why. */
  91. if (errno != EEXIST) {
  92. /* Hmm, something happened that we weren't prepared to handle */
  93. fprintf(stderr, ERROR_ACCESSING_LOCKFILE, lockfile);
  94. return -1;
  95. }
  96. while(1) {
  97. /* Try to grab the lockfile NUM_TRIES times waiting WAIT_TIME milliseconds after each try */
  98. t.tv_sec = 0;
  99. t.tv_usec = WAIT_TIME * 1000;
  100. for(x = 0; x < NUM_TRIES; x++) {
  101. if ((fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0664)) != -1) {
  102. /* Got the lock */
  103. write(fd, (void *) &pid, sizeof(pid_t));
  104. close(fd);
  105. return 0;
  106. }
  107. select(0, NULL, NULL, NULL, &t);
  108. }
  109. /* We still haven't got the lockfile. Find out who owns it and see if they are still up */
  110. if ((fd = open(lockfile, O_RDONLY)) != -1) {
  111. size_t nb_bytes=0;
  112. nb_bytes = read(fd, (void *) &owning_pid, sizeof(pid_t));
  113. if ( (nb_bytes != (size_t)(sizeof(pid_t)) ) || (owning_pid == 0) || (kill(owning_pid, 0) != 0 && errno == ESRCH) ) {
  114. /* The process that owns the lock is dead. Try to remove the old lockfile. */
  115. if (unlink(lockfile) != 0) {
  116. /* Unable to remove the stale lockfile. */
  117. fprintf(stderr, LOCKFILE_DEAD_OWNER, lockfile, owning_pid);
  118. return -1;
  119. }
  120. if (removed_lockfile) {
  121. /* We already removed the lockfile once. Best thing to do is give up. */
  122. /* I'm not sure what should be given as an error here */
  123. fprintf(stderr, UNABLE_TO_GET_LOCKFILE, lockfile);
  124. return -1;
  125. } else {
  126. removed_lockfile = 1;
  127. }
  128. } else {
  129. /* It looks like the owner of the lockfile is still up and running. */
  130. fprintf(stderr, LOCKFILE_ALREADY_OWNED, owning_pid);
  131. return -1;
  132. }
  133. }
  134. }
  135. }
  136. static void
  137. release_lockfile()
  138. {
  139. char lockfile[MAXPATHLEN];
  140. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  141. /* This function assumes that the caller owns the lock, it doesn't check to make sure! */
  142. snprintf(lockfile, sizeof(lockfile), "%s/%s", slapdFrontendConfig->lockdir, LOCK_FILE);
  143. lockfile[sizeof(lockfile)-1] = (char)0;
  144. unlink(lockfile);
  145. }
  146. /* Takes the pid of a process. Returns 1 if the process seems
  147. * to be up, otherwise it returns 0.
  148. */
  149. static int
  150. is_process_up(pid_t pid)
  151. {
  152. if (kill(pid, 0) == -1 && errno == ESRCH) {
  153. return 0;
  154. } else {
  155. return 1;
  156. }
  157. }
  158. /* Make sure the directory 'dir' exists and is owned bye the user
  159. * the server runs as. Returns 0 if everything is ok.
  160. */
  161. static int
  162. make_sure_dir_exists(char *dir)
  163. {
  164. struct passwd* pw;
  165. struct stat stat_buffer;
  166. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  167. /* Make sure it exists */
  168. if (PR_MkDir(dir, 0755) != PR_SUCCESS) {
  169. PRErrorCode prerr = PR_GetError();
  170. if (prerr != PR_FILE_EXISTS_ERROR) {
  171. LDAPDebug(LDAP_DEBUG_ANY, FILE_CREATE_ERROR, dir, prerr, slapd_pr_strerror(prerr));
  172. return 1;
  173. }
  174. }
  175. /* Make sure it's owned by the correct user */
  176. if (slapdFrontendConfig->localuser != NULL &&
  177. slapdFrontendConfig->localuserinfo != NULL) {
  178. pw = slapdFrontendConfig->localuserinfo;
  179. if (chown(dir, pw->pw_uid, -1) == -1) {
  180. stat(dir, &stat_buffer);
  181. if (stat_buffer.st_uid != pw->pw_uid) {
  182. LDAPDebug(LDAP_DEBUG_ANY, CHOWN_WARNING, dir, 0, 0);
  183. return 1;
  184. }
  185. }
  186. }
  187. return 0;
  188. }
  189. /* Creates a file in the directory 'dir_name' whose name is the
  190. * pid for this process.
  191. */
  192. static void
  193. add_this_process_to(char *dir_name)
  194. {
  195. char file_name[MAXPATHLEN];
  196. struct passwd* pw;
  197. struct stat stat_buffer;
  198. PRFileDesc* prfd;
  199. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  200. snprintf(file_name, sizeof(file_name), "%s/%d", dir_name, getpid());
  201. file_name[sizeof(file_name)-1] = (char)0;
  202. if ((prfd = PR_Open(file_name, PR_RDWR | PR_CREATE_FILE, 0666)) == NULL) {
  203. LDAPDebug(LDAP_DEBUG_ANY, FILE_CREATE_WARNING, file_name, 0, 0);
  204. return;
  205. }
  206. /* Make sure the owner is of the file is the user the server
  207. * runs as. */
  208. if (slapdFrontendConfig->localuser != NULL &&
  209. slapdFrontendConfig->localuserinfo != NULL) {
  210. pw = slapdFrontendConfig->localuserinfo;
  211. if (chown(file_name, pw->pw_uid, -1) == -1) {
  212. stat(file_name, &stat_buffer);
  213. if (stat_buffer.st_uid != pw->pw_uid) {
  214. LDAPDebug(LDAP_DEBUG_ANY, CHOWN_WARNING, file_name, 0, 0);
  215. }
  216. }
  217. }
  218. PR_Close(prfd);
  219. }
  220. /* The directory 'dir_name' is expected to contain files whose
  221. * names are the pid of running slapd processes. This
  222. * function will check each entry in the directory and remove
  223. * any files that represent processes that don't exist.
  224. * Returns 0 if there are no processes represented, or
  225. * the pid of one of the processes.
  226. */
  227. static long
  228. sample_and_update(char *dir_name)
  229. {
  230. PRDir *dir;
  231. PRDirEntry *entry;
  232. pid_t pid;
  233. long result = 0;
  234. char *endp;
  235. char file_name[MAXPATHLEN];
  236. if ((dir = PR_OpenDir(dir_name)) == NULL) {
  237. return 0;
  238. }
  239. while((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
  240. pid = (pid_t) strtol(entry->name, &endp, 0);
  241. if (*endp != '\0') {
  242. /* not quite sure what this file was, but we
  243. * didn't put it there */
  244. continue;
  245. }
  246. if (is_process_up(pid)) {
  247. result = (long) pid;
  248. } else {
  249. PR_snprintf(file_name, MAXPATHLEN, "%s/%s", dir_name, entry->name);
  250. PR_Delete(file_name);
  251. }
  252. }
  253. PR_CloseDir(dir);
  254. return result;
  255. }
  256. /* Removes any stale pid entries and the pid entry for this
  257. * process from the directory 'dir_name'.
  258. */
  259. static void
  260. remove_and_update(char *dir_name)
  261. {
  262. /* since this is called from an atexit function, we can't use
  263. * NSPR. */
  264. DIR *dir;
  265. struct dirent *entry;
  266. pid_t pid;
  267. pid_t our_pid;
  268. char *endp;
  269. char file_name[MAXPATHLEN];
  270. /* get our pid */
  271. our_pid = getpid();
  272. if ((dir = opendir(dir_name)) == NULL) {
  273. return;
  274. }
  275. while((entry = readdir(dir)) != NULL) {
  276. /* skip dot and dot-dot */
  277. if (strcmp(entry->d_name, ".") == 0 ||
  278. strcmp(entry->d_name, "..") == 0)
  279. continue;
  280. pid = (pid_t) strtol(entry->d_name, &endp, 0);
  281. if (*endp != '\0') {
  282. /* not quite sure what this file was, but we
  283. * didn't put it there */
  284. continue;
  285. }
  286. if (!is_process_up(pid) || pid == our_pid) {
  287. PR_snprintf(file_name, sizeof(file_name), "%s/%s", dir_name, entry->d_name);
  288. unlink(file_name);
  289. }
  290. }
  291. closedir(dir);
  292. }
  293. /* Walks through all the pid directories and clears any stale
  294. * pids. It also removes the files for this process.
  295. */
  296. void
  297. remove_slapd_process()
  298. {
  299. char import_dir[MAXPATHLEN];
  300. char export_dir[MAXPATHLEN];
  301. char server_dir[MAXPATHLEN];
  302. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  303. /* Create the name of the directories that hold the pids of the currently running
  304. * ns-slapd processes */
  305. snprintf(import_dir, sizeof(import_dir), "%s/%s", slapdFrontendConfig->lockdir, IMPORT_DIR);
  306. import_dir[sizeof(import_dir)-1] = (char)0;
  307. snprintf(export_dir, sizeof(export_dir), "%s/%s", slapdFrontendConfig->lockdir, EXPORT_DIR);
  308. export_dir[sizeof(export_dir)-1] = (char)0;
  309. snprintf(server_dir, sizeof(server_dir), "%s/%s", slapdFrontendConfig->lockdir, SERVER_DIR);
  310. server_dir[sizeof(server_dir)-1] = (char)0;
  311. /* Grab the lockfile */
  312. if (grab_lockfile() != 0) {
  313. /* Unable to grab the lockfile */
  314. return;
  315. }
  316. remove_and_update(import_dir);
  317. remove_and_update(export_dir);
  318. remove_and_update(server_dir);
  319. release_lockfile();
  320. }
  321. int
  322. add_new_slapd_process(int exec_mode, int r_flag, int skip_flag)
  323. {
  324. char import_dir[MAXPATHLEN];
  325. char export_dir[MAXPATHLEN];
  326. char server_dir[MAXPATHLEN];
  327. int running, importing, exporting;
  328. int result = 0;
  329. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  330. if (skip_flag) {
  331. return 0;
  332. }
  333. /* Create the name of the directories that hold the pids of the currently running
  334. * ns-slapd processes */
  335. snprintf(import_dir, sizeof(import_dir), "%s/%s", slapdFrontendConfig->lockdir, IMPORT_DIR);
  336. import_dir[sizeof(import_dir)-1] = (char)0;
  337. snprintf(export_dir, sizeof(export_dir), "%s/%s", slapdFrontendConfig->lockdir, EXPORT_DIR);
  338. export_dir[sizeof(export_dir)-1] = (char)0;
  339. snprintf(server_dir, sizeof(server_dir), "%s/%s", slapdFrontendConfig->lockdir, SERVER_DIR);
  340. server_dir[sizeof(server_dir)-1] = (char)0;
  341. /* Grab the lockfile */
  342. if (grab_lockfile() != 0) {
  343. /* Unable to grab the lockfile */
  344. return -1;
  345. }
  346. /* Make sure the directories exist */
  347. if (make_sure_dir_exists(slapdFrontendConfig->lockdir) != 0 ||
  348. make_sure_dir_exists(import_dir) != 0 ||
  349. make_sure_dir_exists(export_dir) != 0 ||
  350. make_sure_dir_exists(server_dir) != 0) {
  351. release_lockfile();
  352. return -1;
  353. }
  354. /* Go through the directories and find out what's going on.
  355. * Clear any stale pids encountered. */
  356. importing = sample_and_update(import_dir);
  357. exporting = sample_and_update(export_dir);
  358. running = sample_and_update(server_dir);
  359. switch (exec_mode) {
  360. case SLAPD_EXEMODE_SLAPD:
  361. if (running) {
  362. result = -1;
  363. LDAPDebug(LDAP_DEBUG_ANY, NO_SERVER_DUE_TO_SERVER, running, 0, 0);
  364. } else if (importing) {
  365. result = -1;
  366. LDAPDebug(LDAP_DEBUG_ANY, NO_SERVER_DUE_TO_IMPORT, importing, 0, 0);
  367. } else {
  368. add_this_process_to(server_dir);
  369. result = 0;
  370. }
  371. break;
  372. case SLAPD_EXEMODE_DB2LDIF:
  373. if (r_flag) {
  374. /* When the -r flag is used in db2ldif we need to make sure
  375. * we get a consistent snapshot of the server. As a result
  376. * it needs to run by itself, so no other slapd process can
  377. * change the database while it is running. */
  378. if (running || importing) {
  379. LDAPDebug(LDAP_DEBUG_ANY, NO_DB2LDIFR_DUE_TO_USE, 0, 0, 0);
  380. result = -1;
  381. } else {
  382. /* Even though this is really going to export code, we will
  383. * but it in the importing dir so no other process can change
  384. * things while we are doing ldif2db with the -r flag. */
  385. add_this_process_to(import_dir);
  386. result = 0;
  387. }
  388. } else {
  389. if (importing) {
  390. LDAPDebug(LDAP_DEBUG_ANY, NO_DB2LDIF_DUE_TO_IMPORT, importing, 0, 0);
  391. result = -1;
  392. } else {
  393. add_this_process_to(export_dir);
  394. result = 0;
  395. }
  396. }
  397. break;
  398. case SLAPD_EXEMODE_DB2ARCHIVE:
  399. if (importing) {
  400. LDAPDebug(LDAP_DEBUG_ANY, NO_DB2BAK_DUE_TO_IMPORT, importing, 0, 0);
  401. result = -1;
  402. } else {
  403. add_this_process_to(export_dir);
  404. result = 0;
  405. }
  406. break;
  407. case SLAPD_EXEMODE_ARCHIVE2DB:
  408. case SLAPD_EXEMODE_LDIF2DB:
  409. if (running || importing || exporting) {
  410. LDAPDebug(LDAP_DEBUG_ANY, NO_IMPORT_DUE_TO_USE, 0, 0, 0);
  411. result = -1;
  412. } else {
  413. add_this_process_to(import_dir);
  414. result = 0;
  415. }
  416. break;
  417. case SLAPD_EXEMODE_DB2INDEX:
  418. if (running || importing || exporting) {
  419. LDAPDebug(LDAP_DEBUG_ANY, NO_DB2INDEX_DUE_TO_USE, 0, 0, 0);
  420. result = -1;
  421. } else {
  422. add_this_process_to(import_dir);
  423. result = 0;
  424. }
  425. break;
  426. case SLAPD_EXEMODE_UPGRADEDB:
  427. if (running || importing || exporting) {
  428. LDAPDebug(LDAP_DEBUG_ANY, NO_UPGRADEDB_DUE_TO_USE, 0, 0, 0);
  429. result = -1;
  430. } else {
  431. add_this_process_to(import_dir);
  432. result = 0;
  433. }
  434. break;
  435. case SLAPD_EXEMODE_UPGRADEDNFORMAT:
  436. if (running || importing || exporting) {
  437. LDAPDebug(LDAP_DEBUG_ANY, NO_UPGRADEDNFORMAT_DUE_TO_USE, 0, 0, 0);
  438. result = -1;
  439. } else {
  440. add_this_process_to(import_dir);
  441. result = 0;
  442. }
  443. break;
  444. case SLAPD_EXEMODE_DBTEST:
  445. if (running || importing || exporting) {
  446. LDAPDebug(LDAP_DEBUG_ANY, NO_DBTEST_DUE_TO_USE, 0, 0, 0);
  447. result = -1;
  448. } else {
  449. add_this_process_to(import_dir);
  450. result = 0;
  451. }
  452. break;
  453. }
  454. release_lockfile();
  455. if (result == 0) {
  456. atexit(remove_slapd_process);
  457. }
  458. return result;
  459. }
  460. /* is_slapd_running()
  461. * returns 1 if slapd is running, 0 if not, -1 on error
  462. */
  463. int
  464. is_slapd_running() {
  465. char server_dir[MAXPATHLEN];
  466. slapdFrontendConfig_t *cfg = getFrontendConfig();
  467. int running = 0;
  468. snprintf(server_dir, sizeof(server_dir), "%s/%s", cfg->lockdir, SERVER_DIR);
  469. server_dir[sizeof(server_dir)-1] = (char)0;
  470. /* Grab the lockfile */
  471. if (grab_lockfile() != 0) {
  472. /* Unable to grab the lockfile */
  473. return -1;
  474. }
  475. /* Make sure the directories exist */
  476. if (make_sure_dir_exists(cfg->lockdir) != 0 ||
  477. make_sure_dir_exists(server_dir) != 0) {
  478. release_lockfile();
  479. return -1;
  480. }
  481. running = sample_and_update(server_dir);
  482. release_lockfile();
  483. return running;
  484. }
  485. #else /* _WIN32 */
  486. /* The NT version of this code */
  487. /* Returns 1 if the mutex named 'mutexName' otherwise it
  488. * returns 0
  489. */
  490. int
  491. mutex_exists( char *mutexName )
  492. {
  493. if ( OpenMutex( SYNCHRONIZE, FALSE, mutexName ) == NULL ) {
  494. return( 0 );
  495. } else {
  496. return( 1 );
  497. }
  498. }
  499. /* is_slapd_running():
  500. * returns 1 if slapd is running, 0 if not
  501. */
  502. int
  503. is_slapd_running() {
  504. char mutexName[ MAXPATHLEN + 1 ];
  505. char serverMutexName[ MAXPATHLEN + 1 ];
  506. int result = 0;
  507. slapdFrontendConfig_t *cfg = getFrontendConfig();
  508. strncpy( mutexName, cfg->lockdir, MAXPATHLEN );
  509. strncpy( serverMutexName, cfg->lockdir, MAXPATHLEN );
  510. mutexName[ MAXPATHLEN ] = '\0';
  511. serverMutexName[ MAXPATHLEN ] = '\0';
  512. strcat( serverMutexName, "/server" );
  513. return mutex_exists ( serverMutexName );
  514. }
  515. static void fix_mutex_name(char *name)
  516. {
  517. /* On NT mutex names cannot contain the '\' character.
  518. * This functions replaces '\' with '/' in the supplied
  519. * name. */
  520. int x;
  521. for (x = 0; name[x] != '\0'; x++) {
  522. if ('\\' == name[x]) {
  523. name[x] = '/';
  524. }
  525. }
  526. }
  527. /*
  528. * We retain any opened handle to the mutex we create here,
  529. * to use when we shutdown, to delete the mutex prior to
  530. * signaling that we've exited.
  531. */
  532. static HANDLE open_mutex = NULL;
  533. /*
  534. * Call this to clean up the locks, before signaling
  535. * that the server is down.
  536. */
  537. void
  538. remove_slapd_process()
  539. {
  540. if (open_mutex) {
  541. CloseHandle(open_mutex);
  542. }
  543. }
  544. /* This function makes sure different instances of slapd don't
  545. * run in conflicting modes at the same time. The WIN32 version
  546. * uses mutexes as names that the kernel handles. Basically there
  547. * is a server mutex, and import mutex, and an export mutex. If
  548. * the server mutex exists, then the server is running. If the
  549. * import mutex exists, then either ldif2db or bak2db is running.
  550. * If the export mutex exists, then one or more of db2ldif or db2bak
  551. * are running. There is also a mutex that is actually locked when
  552. * checking the existence of the other mutexes. The OS will
  553. * automatically remove a mutex if no process has a handle on it.
  554. * returns a 0 if it is ok for the process to run
  555. * returns a -1 if the process can't run do to a conflict with other
  556. * slapd processes
  557. */
  558. int
  559. add_new_slapd_process(int exec_mode, int r_flag, int skip_flag)
  560. {
  561. char mutexName[ MAXPATHLEN + 1 ];
  562. char serverMutexName[ MAXPATHLEN + 1 ];
  563. char importMutexName[ MAXPATHLEN + 1 ];
  564. char exportMutexName[ MAXPATHLEN + 1 ];
  565. HANDLE mutex;
  566. SECURITY_ATTRIBUTES mutexAttributes;
  567. PSECURITY_DESCRIPTOR pSD;
  568. LPVOID lpMsgBuf;
  569. int result = 0;
  570. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  571. if (skip_flag) {
  572. return 0;
  573. }
  574. /* Create the names for the mutexes */
  575. PL_strncpyz(mutexName, slapdFrontendConfig->lockdir, sizeof(mutexName));
  576. /* Make sure the name of the mutex is legal. */
  577. fix_mutex_name(mutexName);
  578. PR_snprintf(serverMutexName, sizeof(serverMutexName), "%s/server", mutexName);
  579. PR_snprintf(importMutexName, sizeof(importMutexName), "%s/import", mutexName);
  580. PR_snprintf(exportMutexName, sizeof(exportMutexName), "%s/export", mutexName);
  581. /* Fill in the security crap for the mutex */
  582. pSD = (PSECURITY_DESCRIPTOR)slapi_ch_malloc( sizeof( SECURITY_DESCRIPTOR ) );
  583. InitializeSecurityDescriptor( pSD, SECURITY_DESCRIPTOR_REVISION );
  584. SetSecurityDescriptorDacl( pSD, TRUE, NULL, FALSE );
  585. mutexAttributes.nLength = sizeof( mutexAttributes );
  586. mutexAttributes.lpSecurityDescriptor = pSD;
  587. mutexAttributes.bInheritHandle = FALSE;
  588. /* Get a handle to the main mutex */
  589. if ( ( mutex = CreateMutex( &mutexAttributes, FALSE, mutexName ) ) == NULL ) {
  590. FormatMessage(
  591. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  592. NULL,
  593. GetLastError(),
  594. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
  595. (LPTSTR) &lpMsgBuf,
  596. 0,
  597. NULL
  598. );
  599. LDAPDebug( LDAP_DEBUG_ANY, CREATE_MUTEX_ERROR, lpMsgBuf, 0, 0 );
  600. LocalFree( lpMsgBuf );
  601. exit( 1 );
  602. }
  603. /* Lock the main mutex */
  604. if ( WaitForSingleObject( mutex, INFINITE ) == WAIT_FAILED ) {
  605. FormatMessage(
  606. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  607. NULL,
  608. GetLastError(),
  609. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
  610. (LPTSTR) &lpMsgBuf,
  611. 0,
  612. NULL
  613. );
  614. LDAPDebug( LDAP_DEBUG_ANY, WAIT_ERROR, lpMsgBuf, 0, 0 );
  615. LocalFree( lpMsgBuf );
  616. exit( 1 );
  617. }
  618. switch (exec_mode) {
  619. case SLAPD_EXEMODE_SLAPD:
  620. if ( mutex_exists( serverMutexName ) ||
  621. mutex_exists( importMutexName ) ) {
  622. LDAPDebug( LDAP_DEBUG_ANY, NO_SERVER_DUE_TO_USE, 0, 0, 0);
  623. result = -1;
  624. } else {
  625. open_mutex = CreateMutex( &mutexAttributes, FALSE, serverMutexName );
  626. result = 0;
  627. }
  628. break;
  629. case SLAPD_EXEMODE_DB2LDIF:
  630. if (r_flag) {
  631. /* When the -r flag is used in db2ldif we need to make sure
  632. * we get a consistent snapshot of the server. As a result
  633. * it needs to run by itself, so no other slapd process can
  634. * change the database while it is running. */
  635. if ( mutex_exists( serverMutexName ) ||
  636. mutex_exists( importMutexName ) ||
  637. mutex_exists( exportMutexName ) ) {
  638. LDAPDebug(LDAP_DEBUG_ANY, NO_DB2LDIFR_DUE_TO_USE, 0, 0, 0);
  639. result = -1;
  640. } else {
  641. CreateMutex( &mutexAttributes, FALSE, exportMutexName );
  642. result = 0;
  643. }
  644. break;
  645. }
  646. case SLAPD_EXEMODE_DB2ARCHIVE:
  647. if ( mutex_exists( importMutexName ) ) {
  648. LDAPDebug(LDAP_DEBUG_ANY, NO_EXPORT_DUE_TO_IMPORT, 0, 0, 0);
  649. result = -1;
  650. } else {
  651. CreateMutex( &mutexAttributes, FALSE, exportMutexName );
  652. result = 0;
  653. }
  654. break;
  655. case SLAPD_EXEMODE_ARCHIVE2DB:
  656. case SLAPD_EXEMODE_LDIF2DB:
  657. if ( mutex_exists( serverMutexName ) ||
  658. mutex_exists( importMutexName ) ||
  659. mutex_exists( exportMutexName ) ) {
  660. LDAPDebug(LDAP_DEBUG_ANY, NO_IMPORT_DUE_TO_USE, 0, 0, 0);
  661. result = -1;
  662. } else {
  663. CreateMutex( &mutexAttributes, FALSE, importMutexName );
  664. result = 0;
  665. }
  666. break;
  667. case SLAPD_EXEMODE_UPGRADEDB:
  668. if ( mutex_exists( serverMutexName ) ||
  669. mutex_exists( importMutexName ) ||
  670. mutex_exists( exportMutexName ) ) {
  671. LDAPDebug(LDAP_DEBUG_ANY, NO_UPGRADEDB_DUE_TO_USE, 0, 0, 0);
  672. result = -1;
  673. } else {
  674. CreateMutex( &mutexAttributes, FALSE, importMutexName );
  675. result = 0;
  676. }
  677. break;
  678. case SLAPD_EXEMODE_DBTEST:
  679. if ( mutex_exists( serverMutexName ) ||
  680. mutex_exists( importMutexName ) ||
  681. mutex_exists( exportMutexName ) ) {
  682. LDAPDebug(LDAP_DEBUG_ANY, NO_DBTEST_DUE_TO_USE, 0, 0, 0);
  683. result = -1;
  684. } else {
  685. CreateMutex( &mutexAttributes, FALSE, importMutexName );
  686. result = 0;
  687. }
  688. break;
  689. }
  690. /* release the main mutex */
  691. ReleaseMutex( mutex );
  692. slapi_ch_free((void**)&pSD );
  693. return( result );
  694. }
  695. #endif /* _WIN32 */