--- app_voicemail.c 2004-12-15 14:49:37.000000000 -0800 +++ app_voicemail.c.new 2004-12-15 19:41:35.920149240 -0800 @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include "../asterisk.h" #include "../astconf.h" @@ -303,6 +305,11 @@ static char callcontext[80]; static char exitcontext[80]; +static uid_t mailboxuid; +static gid_t mailboxgid; +static mode_t dirMode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP; +static mode_t filMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64]; @@ -323,6 +330,63 @@ LOCAL_USER_DECL; +static void set_owner_and_group(const char* pathname) +{ + uid_t euid, ruid; + int status; + + /* Remember the real and effective user IDs. */ + ruid = getuid (); + euid = geteuid (); + +#ifdef _POSIX_SAVED_IDS + status = seteuid (0); +#else + status = setreuid (ruid, 0); +#endif + if (status < 0) + return; + if (chown(pathname, mailboxuid, mailboxgid)) { + ast_log(LOG_WARNING, "chown '%s' failed: %s\n", + pathname, strerror(errno)); + } +#ifdef _POSIX_SAVED_IDS + status = seteuid (euid); +#else + status = setreuid (ruid, euid); +#endif +} + +static void set_owner_and_group_all(const char* dir, int msgnum) +{ + DIR *vmdir = NULL; + struct dirent *vment = NULL; + char fn[32]; + char pn[1024]; + snprintf(fn, sizeof(fn), "msg%04d", msgnum); + + if (sizeof(dir) + 11 >= sizeof(pn)) { + ast_log(LOG_WARNING, "directory name too long to set owner and group, skipping\n"); + return; + } + if ((vmdir = opendir(dir))) { + while ((vment = readdir(vmdir))) { + if (!strncmp(vment->d_name, fn, 7)) { + strcpy(pn, dir); + pn[strlen(dir)] = '/'; + pn[strlen(dir)+1] = 0; + strcat(pn, vment->d_name); + if (chmod(pn, filMode)) { + ast_log(LOG_WARNING, "chmod '%s' failed: %s\n", + pn, strerror(errno)); + } + set_owner_and_group(pn); + } + } + closedir(vmdir); + } +} + static void populate_defaults(struct ast_vm_user *vmu) { vmu->attach = -1; @@ -1345,7 +1409,7 @@ ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile); return -1; } - if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) { + if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, filMode)) < 0) { ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile); close(ifd); return -1; @@ -1370,10 +1434,12 @@ } while (len); close(ifd); close(ofd); + set_owner_and_group(outfile); return 0; #ifdef HARDLINK_WHEN_POSSIBLE } else { /* Hard link succeeded */ + set_owner_and_group(outfile); return 0; } #endif @@ -1897,16 +1963,19 @@ make_dir(todir, sizeof(todir), recip->context, "", ""); /* It's easier just to try to make it than to check for its existence */ - if (mkdir(todir, 0700) && (errno != EEXIST)) + if (mkdir(todir, dirMode) && (errno != EEXIST)) ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno)); + set_owner_and_group(todir); make_dir(todir, sizeof(todir), recip->context, recip->mailbox, ""); /* It's easier just to try to make it than to check for its existence */ - if (mkdir(todir, 0700) && (errno != EEXIST)) + if (mkdir(todir, dirMode) && (errno != EEXIST)) ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno)); + set_owner_and_group(todir); make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX"); - if (mkdir(todir, 0700) && (errno != EEXIST)) + if (mkdir(todir, dirMode) && (errno != EEXIST)) ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno)); + set_owner_and_group(todir); make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox); make_file(frompath, sizeof(frompath), fromdir, msgnum); recipmsgnum = 0; @@ -2002,15 +2071,18 @@ DISPOSE(tempfile, -1); make_dir(dir, sizeof(dir), vmu->context, "", ""); /* It's easier just to try to make it than to check for its existence */ - if (mkdir(dir, 0700) && (errno != EEXIST)) + if (mkdir(dir, dirMode) && (errno != EEXIST)) ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + set_owner_and_group(dir); make_dir(dir, sizeof(dir), vmu->context, ext, ""); /* It's easier just to try to make it than to check for its existence */ - if (mkdir(dir, 0700) && (errno != EEXIST)) + if (mkdir(dir, dirMode) && (errno != EEXIST)) ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + set_owner_and_group(dir); make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX"); - if (mkdir(dir, 0700) && (errno != EEXIST)) + if (mkdir(dir, dirMode) && (errno != EEXIST)) ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + set_owner_and_group(dir); /* Check current or macro-calling context for special extensions */ if (!ast_strlen_zero(vmu->exit)) { @@ -2173,6 +2245,8 @@ /* 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; } + set_owner_and_group(txtfile); + set_owner_and_group_all(dir, msgnum); /* Are there to be more recipients of this message? */ while (tmpptr) { struct ast_vm_user recipu, *recip; @@ -2256,7 +2330,8 @@ int x; make_file(sfn, sizeof(sfn), dir, msg); make_dir(ddir, sizeof(ddir), context, username, dbox); - mkdir(ddir, 0700); + mkdir(ddir, dirMode); + set_owner_and_group(ddir); for (x=0;xlanguage && !ast_strlen_zero(vmu->language)) strncpy(chan->language, vmu->language, sizeof(chan->language)-1); snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context); - mkdir(vms.curdir, 0700); + mkdir(vms.curdir, dirMode); + set_owner_and_group(vms.curdir); snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context, vms.username); - mkdir(vms.curdir, 0700); + mkdir(vms.curdir, dirMode); + set_owner_and_group(vms.curdir); /* Retrieve old and new message counts */ open_mailbox(&vms, vmu, 1); vms.oldmessages = vms.lastmsg + 1; @@ -4984,6 +5061,11 @@ char *callbackcxt = NULL; char *exitcxt = NULL; char *extpc; + char *mailowner; + char *mailgroup; + char *mode; + struct passwd *pwinfo; + struct group *grinfo; int x; int tmpadsi[4]; @@ -5334,6 +5416,52 @@ tmpread = tmpwrite+len; } } + /* These define the owner and group of vm files to be accessible from the web interface */ + pwinfo = getpwuid(geteuid()); + mailboxuid = pwinfo->pw_uid; + if ((mailowner = ast_variable_retrieve(cfg, "general", "mailboxowner"))) { + pwinfo = getpwnam(mailowner); + if (pwinfo == NULL) { + ast_log(LOG_WARNING, "Invalid mailboxowner specified: %s\n", mailowner); + } else { + mailboxuid = pwinfo->pw_uid; + ast_log(LOG_DEBUG, "found mailboxowner: %s\n", mailowner); + } + } + grinfo = getgrgid(getegid()); + mailboxgid = grinfo->gr_gid; + if ((mailgroup = ast_variable_retrieve(cfg, "general", "mailboxgroup"))) { + grinfo = getgrnam(mailgroup); + if (grinfo == NULL) { + ast_log(LOG_WARNING, "Invalid mailboxgroup specified: %s\n", mailgroup); + } else { + mailboxgid = grinfo->gr_gid; + ast_log(LOG_DEBUG, "found mailgroup: %s\n", mailgroup); + } + } + + if ((mode = ast_variable_retrieve(cfg, "general", "mailboxdirmode"))) { + char *eptr; + mode_t tmp = strtol(mode, &eptr, 0); + if (*eptr != 0) { + ast_log(LOG_WARNING, "Invalid directory permissions: %s\n", mode); + } else { + dirMode = tmp; + ast_log(LOG_DEBUG, "found directory permissions: %s\n", mode); + } + } + + if ((mode = ast_variable_retrieve(cfg, "general", "mailboxfilemode"))) { + char *eptr; + mode_t tmp = strtol(mode, &eptr, 0); + if (*eptr != 0) { + ast_log(LOG_WARNING, "Invalid file permissions: %s\n", mode); + } else { + filMode = tmp; + ast_log(LOG_DEBUG, "found file permissions: %s\n", mode); + } + } + ast_destroy(cfg); ast_mutex_unlock(&vmlock); return 0;