fix up lock breakage from bug #4245

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6125 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.2-netsec
Kevin P. Fleming 21 years ago
parent f62a613d24
commit 9a7a5d5623

26
app.c

@ -1095,36 +1095,42 @@ int ast_separate_app_args(char *buf, char delim, char **array, int arraylen)
return x; return x;
} }
int ast_lock_path(const char *path) enum AST_LOCK_RESULT ast_lock_path(const char *path)
{ {
char *s; char *s;
char *fs; char *fs;
int res; int res;
int fd; int fd;
time_t start; time_t start;
s = alloca(strlen(path) + 10); s = alloca(strlen(path) + 10);
fs = alloca(strlen(path) + 20); fs = alloca(strlen(path) + 20);
if (!fs || !s) { if (!fs || !s) {
ast_log(LOG_WARNING, "Out of memory!\n"); ast_log(LOG_WARNING, "Out of memory!\n");
return -1; return AST_LOCK_FAILURE;
} }
snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
snprintf(fs, strlen(path) + 19, "%s/.lock-%08x", path, rand());
fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600); fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno)); fprintf(stderr, "Unable to create lock file '%s': %s\n", path, strerror(errno));
return -1; return AST_LOCK_PATH_NOT_FOUND;
} }
close(fd); close(fd);
snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
snprintf(s, strlen(path) + 9, "%s/.lock", path);
time(&start); time(&start);
while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5)) while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
usleep(1); usleep(1);
if (res < 0) { if (res) {
ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno)); ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
return AST_LOCK_TIMEOUT;
} else {
unlink(fs);
ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
return AST_LOCK_SUCCESS;
} }
unlink(fs);
ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
return res;
} }
int ast_unlock_path(const char *path) int ast_unlock_path(const char *path)

@ -692,6 +692,19 @@ static int make_file(char *dest, int len, char *dir, int num)
return snprintf(dest, len, "%s/msg%04d", dir, num); return snprintf(dest, len, "%s/msg%04d", dir, num);
} }
/* only return failure if ast_lock_path returns 'timeout',
not if the path does not exist or any other reason
*/
static int vm_lock_path(const char *path)
{
switch (ast_lock_path(path)) {
case AST_LOCK_TIMEOUT:
return -1;
default:
return 0;
}
}
#ifdef USE_ODBC_STORAGE #ifdef USE_ODBC_STORAGE
static int retrieve_file(char *dir, int msgnum) static int retrieve_file(char *dir, int msgnum)
@ -982,9 +995,9 @@ yuck:
*/ */
static int count_messages(struct ast_vm_user *vmu, char *dir) static int count_messages(struct ast_vm_user *vmu, char *dir)
{ {
int res = 0; int res;
res = last_message_index(vmu, dir) + 1; res = last_message_index(vmu, dir);
return res >= 0 ? res + 1 : res; return res >= 0 ? res + 1 : res;
} }
@ -1259,23 +1272,19 @@ static int count_messages(struct ast_vm_user *vmu, char *dir)
DIR *vmdir = NULL; DIR *vmdir = NULL;
struct dirent *vment = NULL; struct dirent *vment = NULL;
if (!ast_lock_path(dir)) { if (vm_lock_path(dir))
if ((vmdir = opendir(dir))) {
while ((vment = readdir(vmdir)))
{
if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,".txt",4))
{
vmcount++;
}
}
closedir(vmdir);
}
ast_unlock_path(dir);
return vmcount;
} else {
return ERROR_LOCK_PATH; return ERROR_LOCK_PATH;
if ((vmdir = opendir(dir))) {
while ((vment = readdir(vmdir))) {
if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4))
vmcount++;
}
closedir(vmdir);
} }
ast_unlock_path(dir);
return vmcount;
} }
static void rename_file(char *sfn, char *dfn) static void rename_file(char *sfn, char *dfn)
@ -1354,17 +1363,18 @@ static int last_message_index(struct ast_vm_user *vmu, char *dir)
{ {
int x; int x;
char fn[256]; char fn[256];
if (!ast_lock_path(dir)) {
for (x = 0; x < vmu->maxmsg; x++) { if (vm_lock_path(dir))
make_file(fn, sizeof(fn), dir, x);
if (ast_fileexists(fn, NULL, NULL) < 1)
break;
}
ast_unlock_path(dir);
return x-1;
} else {
return ERROR_LOCK_PATH; return ERROR_LOCK_PATH;
for (x = 0; x < vmu->maxmsg; x++) {
make_file(fn, sizeof(fn), dir, x);
if (ast_fileexists(fn, NULL, NULL) < 1)
break;
} }
ast_unlock_path(dir);
return x - 1;
} }
static int vm_delete(char *file) static int vm_delete(char *file)
@ -1997,24 +2007,24 @@ static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int i
make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox); make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
make_file(frompath, sizeof(frompath), fromdir, msgnum); make_file(frompath, sizeof(frompath), fromdir, msgnum);
if (!ast_lock_path(topath)) {
recipmsgnum = 0; if (vm_lock_path(topath))
do { return ERROR_LOCK_PATH;
make_file(topath, sizeof(topath), todir, recipmsgnum);
if (!EXISTS(todir, recipmsgnum, topath, chan->language)) recipmsgnum = 0;
break; do {
recipmsgnum++; make_file(topath, sizeof(topath), todir, recipmsgnum);
if (!EXISTS(todir, recipmsgnum, topath, chan->language))
break;
recipmsgnum++;
} while (recipmsgnum < recip->maxmsg); } while (recipmsgnum < recip->maxmsg);
if (recipmsgnum < recip->maxmsg) { if (recipmsgnum < recip->maxmsg) {
COPY(fromdir, msgnum, todir, recipmsgnum, frompath, topath); COPY(fromdir, msgnum, todir, recipmsgnum, frompath, topath);
} else {
ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
}
ast_unlock_path(topath);
notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
} else { } else {
return ERROR_LOCK_PATH; ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
} }
ast_unlock_path(topath);
notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
return 0; return 0;
} }
@ -2208,106 +2218,106 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
ast_copy_string(fmt, vmfmts, sizeof(fmt)); ast_copy_string(fmt, vmfmts, sizeof(fmt));
if (!ast_strlen_zero(fmt)) { if (!ast_strlen_zero(fmt)) {
msgnum = 0; msgnum = 0;
if (!ast_lock_path(dir)) {
if (res >= 0) { if (vm_lock_path(dir)) {
/* Unless we're *really* silent, try to send the beep */ free_user(vmu);
res = ast_streamfile(chan, "beep", chan->language); return ERROR_LOCK_PATH;
if (!res) }
res = ast_waitstream(chan, "");
} if (res >= 0) {
do { /* Unless we're *really* silent, try to send the beep */
make_file(fn, sizeof(fn), dir, msgnum); res = ast_streamfile(chan, "beep", chan->language);
if (!EXISTS(dir,msgnum,fn,chan->language)) if (!res)
break; res = ast_waitstream(chan, "");
msgnum++; }
do {
make_file(fn, sizeof(fn), dir, msgnum);
if (!EXISTS(dir,msgnum,fn,chan->language))
break;
msgnum++;
} while (msgnum < vmu->maxmsg); } while (msgnum < vmu->maxmsg);
if (msgnum < vmu->maxmsg) { if (msgnum < vmu->maxmsg) {
/* assign a variable with the name of the voicemail file */
/* assign a variable with the name of the voicemail file */ pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
/* Store information */
/* Store information */ snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
snprintf(txtfile, sizeof(txtfile), "%s.txt", fn); txt = fopen(txtfile, "w+");
txt = fopen(txtfile, "w+"); if (txt) {
if (txt) { get_date(date, sizeof(date));
get_date(date, sizeof(date)); fprintf(txt,
fprintf(txt, ";\n"
";\n" "; Message Information file\n"
"; Message Information file\n" ";\n"
";\n" "[message]\n"
"[message]\n" "origmailbox=%s\n"
"origmailbox=%s\n" "context=%s\n"
"context=%s\n" "macrocontext=%s\n"
"macrocontext=%s\n" "exten=%s\n"
"exten=%s\n" "priority=%d\n"
"priority=%d\n" "callerchan=%s\n"
"callerchan=%s\n" "callerid=%s\n"
"callerid=%s\n" "origdate=%s\n"
"origdate=%s\n" "origtime=%ld\n"
"origtime=%ld\n" "category=%s\n",
"category=%s\n", ext,
ext, chan->context,
chan->context, chan->macrocontext,
chan->macrocontext, chan->exten,
chan->exten, chan->priority,
chan->priority, chan->name,
chan->name, ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"),
ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), date, (long)time(NULL),
date, (long)time(NULL), category ? category : "");
category ? category : ""); } else
} else ast_log(LOG_WARNING, "Error opening text file for output\n");
ast_log(LOG_WARNING, "Error opening text file for output\n"); res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir);
res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir); if (res == '0') {
if (res == '0') { if (txt)
if (txt)
fclose(txt);
goto transfer;
}
if (res > 0)
res = 0;
if (txt) {
fprintf(txt, "duration=%d\n", duration);
fclose(txt); fclose(txt);
} goto transfer;
}
if (res > 0)
res = 0;
if (txt) {
fprintf(txt, "duration=%d\n", duration);
fclose(txt);
}
if (duration < vmminmessage) { if (duration < vmminmessage) {
if (option_verbose > 2) if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage); ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
DELETE(dir,msgnum,fn); DELETE(dir,msgnum,fn);
/* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */ /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
goto leave_vm_out; goto leave_vm_out;
} }
/* Are there to be more recipients of this message? */ /* Are there to be more recipients of this message? */
while (tmpptr) { while (tmpptr) {
struct ast_vm_user recipu, *recip; struct ast_vm_user recipu, *recip;
char *exten, *context; char *exten, *context;
exten = strsep(&tmpptr, "&"); exten = strsep(&tmpptr, "&");
context = strchr(exten, '@'); context = strchr(exten, '@');
if (context) { if (context) {
*context = '\0'; *context = '\0';
context++; context++;
}
if ((recip = find_user(&recipu, context, exten))) {
copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
free_user(recip);
}
} }
if (ast_fileexists(fn, NULL, NULL)) { if ((recip = find_user(&recipu, context, exten))) {
notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name); copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
STORE(dir, msgnum); free_user(recip);
DISPOSE(dir, msgnum);
} }
} else { }
ast_unlock_path(dir); if (ast_fileexists(fn, NULL, NULL)) {
res = ast_streamfile(chan, "vm-mailboxfull", chan->language); notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
if (!res) STORE(dir, msgnum);
res = ast_waitstream(chan, ""); DISPOSE(dir, msgnum);
ast_log(LOG_WARNING, "No more messages possible\n");
} }
} else { } else {
free_user(vmu); ast_unlock_path(dir);
return ERROR_LOCK_PATH; res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
if (!res)
res = ast_waitstream(chan, "");
ast_log(LOG_WARNING, "No more messages possible\n");
} }
} else } else
ast_log(LOG_WARNING, "No format for saving voicemail?\n"); ast_log(LOG_WARNING, "No format for saving voicemail?\n");
@ -2316,8 +2326,7 @@ leave_vm_out:
} else { } else {
ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext); ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
/*Send the call to n+101 priority, where n is the current priority*/ /*Send the call to n+101 priority, where n is the current priority*/
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
chan->priority+=100;
} }
return res; return res;
@ -2332,23 +2341,22 @@ static int resequence_mailbox(struct ast_vm_user *vmu, char *dir)
char sfn[256]; char sfn[256];
char dfn[256]; char dfn[256];
if (!ast_lock_path(dir)) { if (vm_lock_path(dir))
for (x = 0, dest = 0; x < vmu->maxmsg; x++) { return ERROR_LOCK_PATH;
make_file(sfn, sizeof(sfn), dir, x);
if (EXISTS(dir, x, sfn, NULL)) {
if(x != dest) { for (x = 0, dest = 0; x < vmu->maxmsg; x++) {
make_file(dfn, sizeof(dfn), dir, dest); make_file(sfn, sizeof(sfn), dir, x);
RENAME(dir, x, dir, dest, sfn, dfn); if (EXISTS(dir, x, sfn, NULL)) {
}
dest++; if(x != dest) {
make_file(dfn, sizeof(dfn), dir, dest);
RENAME(dir, x, dir, dest, sfn, dfn);
} }
dest++;
} }
ast_unlock_path(dir);
} else {
return ERROR_LOCK_PATH;
} }
ast_unlock_path(dir);
return 0; return 0;
} }
@ -2371,23 +2379,23 @@ static int save_to_folder(struct ast_vm_user *vmu, char *dir, int msg, char *con
make_file(sfn, sizeof(sfn), dir, msg); make_file(sfn, sizeof(sfn), dir, msg);
make_dir(ddir, sizeof(ddir), context, username, dbox); make_dir(ddir, sizeof(ddir), context, username, dbox);
mkdir(ddir, 0700); mkdir(ddir, 0700);
if (!ast_lock_path(ddir)) {
for (x = 0; x < vmu->maxmsg; x++) { if (vm_lock_path(ddir))
make_file(dfn, sizeof(dfn), ddir, x);
if (!EXISTS(ddir, x, dfn, NULL))
break;
}
if (x >= vmu->maxmsg) {
ast_unlock_path(ddir);
return -1;
}
if (strcmp(sfn, dfn)) {
COPY(dir, msg, ddir, x, sfn, dfn);
}
ast_unlock_path(ddir);
} else {
return ERROR_LOCK_PATH; return ERROR_LOCK_PATH;
for (x = 0; x < vmu->maxmsg; x++) {
make_file(dfn, sizeof(dfn), ddir, x);
if (!EXISTS(ddir, x, dfn, NULL))
break;
} }
if (x >= vmu->maxmsg) {
ast_unlock_path(ddir);
return -1;
}
if (strcmp(sfn, dfn)) {
COPY(dir, msg, ddir, x, sfn, dfn);
}
ast_unlock_path(ddir);
return 0; return 0;
} }
@ -3526,45 +3534,49 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
{ {
int x; int x;
int res = 0; int res = 0;
if (vms->lastmsg > -1) {
/* Get the deleted messages fixed */ if (vms->lastmsg <= -1)
if (!ast_lock_path(vms->curdir)) { goto done;
vms->curmsg = -1;
for (x=0;x < vmu->maxmsg;x++) { /* Get the deleted messages fixed */
if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) { if (vm_lock_path(vms->curdir))
/* Save this message. It's not in INBOX or hasn't been heard */ return ERROR_LOCK_PATH;
make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
if (!EXISTS(vms->curdir, x, vms->fn, NULL)) vms->curmsg = -1;
break; for (x=0;x < vmu->maxmsg;x++) {
vms->curmsg++; if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg); /* Save this message. It's not in INBOX or hasn't been heard */
if (strcmp(vms->fn, vms->fn2)) { make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
RENAME(vms->curdir, x, vms->curdir, vms->curmsg, vms->fn, vms->fn2); if (!EXISTS(vms->curdir, x, vms->fn, NULL))
} break;
} else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) { vms->curmsg++;
/* Move to old folder before deleting */ make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
res = save_to_folder(vmu, vms->curdir, x, vmu->context, vms->username, 1); if (strcmp(vms->fn, vms->fn2)) {
if (res == ERROR_LOCK_PATH) { RENAME(vms->curdir, x, vms->curdir, vms->curmsg, vms->fn, vms->fn2);
/* If save failed do not delete the message */
vms->deleted[x] = 0;
vms->heard[x] = 0;
--x;
}
}
} }
for (x = vms->curmsg + 1; x <= vmu->maxmsg; x++) { } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
make_file(vms->fn, sizeof(vms->fn), vms->curdir, x); /* Move to old folder before deleting */
if (!EXISTS(vms->curdir, x, vms->fn, NULL)) res = save_to_folder(vmu, vms->curdir, x, vmu->context, vms->username, 1);
break; if (res == ERROR_LOCK_PATH) {
DELETE(vms->curdir, x, vms->fn); /* If save failed do not delete the message */
vms->deleted[x] = 0;
vms->heard[x] = 0;
--x;
} }
ast_unlock_path(vms->curdir);
} else {
return ERROR_LOCK_PATH;
} }
} }
for (x = vms->curmsg + 1; x <= vmu->maxmsg; x++) {
make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
if (!EXISTS(vms->curdir, x, vms->fn, NULL))
break;
DELETE(vms->curdir, x, vms->fn);
}
ast_unlock_path(vms->curdir);
done:
memset(vms->deleted, 0, sizeof(vms->deleted)); memset(vms->deleted, 0, sizeof(vms->deleted));
memset(vms->heard, 0, sizeof(vms->heard)); memset(vms->heard, 0, sizeof(vms->heard));
return 0; return 0;
} }

@ -139,8 +139,19 @@ int ast_play_and_record(struct ast_channel *chan, const char *playfile, const ch
/* permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults. */ /* permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults. */
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence_ms); int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence_ms);
/* Lock a path */ enum AST_LOCK_RESULT {
int ast_lock_path(const char *path); AST_LOCK_SUCCESS = 0,
AST_LOCK_TIMEOUT = -1,
AST_LOCK_PATH_NOT_FOUND = -2,
AST_LOCK_FAILURE = -3,
};
/*
* \brief Lock a filesystem path.
* \param path the path to be locked
* \return one of AST_LOCK_RESULT values
*/
enum AST_LOCK_RESULT ast_lock_path(const char *path);
/* Unlock a path */ /* Unlock a path */
int ast_unlock_path(const char *path); int ast_unlock_path(const char *path);

Loading…
Cancel
Save