protect_db.c 24 KB

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