|
From: <ton...@us...> - 2003-12-25 02:08:35
|
Update of /cvsroot/serverfilters/script
In directory sc8-pr-cvs1:/tmp/cvs-serv29178
Modified Files:
filtercmd.c
Log Message:
Virtual user lookup; stdin/stdout used instead of filter files; checks ownership of trusted files.
Index: filtercmd.c
===================================================================
RCS file: /cvsroot/serverfilters/script/filtercmd.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** filtercmd.c 14 Dec 2003 20:55:27 -0000 1.5
--- filtercmd.c 25 Dec 2003 02:08:32 -0000 1.6
***************
*** 7,10 ****
--- 7,11 ----
/* define DEBUG for debugging output */
+ #define DEBUG
#include <stdio.h>
***************
*** 18,24 ****
void eperror(register char *);
int rcexists(char *);
! int getrc(char*, char*, uid_t, gid_t);
! int putrc(char*, char*, char*);
! int copy_file(char*, char*);
int validrcpath(char*);
int validtmppath(char*);
--- 19,25 ----
void eperror(register char *);
int rcexists(char *);
! int getrc(char*);
! int putrc(char*, uid_t, gid_t);
! int copy_file(char*, FILE*, char*, FILE*);
int validrcpath(char*);
int validtmppath(char*);
***************
*** 34,40 ****
Thiago Melo de Paula - th...@fa...
*/
! int i, ok;
char cmd[STR_MAX];
char user[STR_MAX];
char passwd[STR_MAX];
char filter_file[STR_MAX];
--- 35,42 ----
Thiago Melo de Paula - th...@fa...
*/
! int err, ok;
char cmd[STR_MAX];
char user[STR_MAX];
+ char real_user[STR_MAX];
char passwd[STR_MAX];
char filter_file[STR_MAX];
***************
*** 44,65 ****
gid_t GID;
! if (!readcredentials(user, passwd, STR_MAX)) {
! return inerror(ERR_NEED_CREDENTIALS);
! }
! if (!readimapserver(imap_server, STR_MAX)) {
! return inerror(ERR_CANT_READ_IMAP_SERVER);
! }
! if (!finduidgid(user, &UID, &GID)) {
! return inerror(ERR_BAD_UID_GID);
! }
if((setgid(GID)) < 0) eperror("setgid");
if((setuid(UID)) < 0) eperror("setuid");
! if (i = checkcredentials(imap_server, user, passwd)) {
! return inerror(i);
! }
strncpy(cmd,argv[1],STR_MAX);
--- 46,66 ----
gid_t GID;
! err = readcredentials(user, passwd, STR_MAX);
! if (err) return inerror(err);
! err = readimapserver(imap_server, STR_MAX);
! if (err) return inerror(err);
! err = readvirtualdomain(user, real_user, STR_MAX);
! if (err) return inerror(err);
!
! err = finduidgid(real_user, &UID, &GID);
! if (err) return inerror(err);
if((setgid(GID)) < 0) eperror("setgid");
if((setuid(UID)) < 0) eperror("setuid");
! err = checkcredentials(imap_server, user, passwd);
! if (err) return inerror(err);
strncpy(cmd,argv[1],STR_MAX);
***************
*** 69,91 ****
} else {
if (!strcmp("getrc",cmd)) {
! if (argc < 4) {
! printf("Usage: filtercmd getrc filter_file temp_file\n");
return ERR_USAGE;
}
strncpy(filter_file, argv[2], STR_MAX);
! strncpy(temp_file, argv[3], STR_MAX);
! return getrc(filter_file, temp_file, UID, GID);
} else if (!strcmp("putrc", cmd)) {
! if (argc < 5) {
! printf("Usage: filtercmd putrc owner temp_file filter_file\n");
return ERR_USAGE;
}
! strncpy(user, argv[2], STR_MAX);
! if(!strcmp(user,"root") && !strcmp(user, "0")){
! return inerror(ERR_USER_IS_ROOT);
! }
! strncpy(temp_file, argv[3], STR_MAX);
! strncpy(filter_file, argv[4], STR_MAX);
! return putrc(user, temp_file, filter_file);
} else if (!strcmp("rcexists",cmd)) {
if (argc < 3) {
--- 70,86 ----
} else {
if (!strcmp("getrc",cmd)) {
! if (argc < 3) {
! printf("Usage: filtercmd getrc filter_file\n");
return ERR_USAGE;
}
strncpy(filter_file, argv[2], STR_MAX);
! return getrc(filter_file);
} else if (!strcmp("putrc", cmd)) {
! if (argc < 3) {
! printf("Usage: filtercmd putrc filter_file\n");
return ERR_USAGE;
}
! strncpy(filter_file, argv[2], STR_MAX);
! return putrc(filter_file, UID, GID);
} else if (!strcmp("rcexists",cmd)) {
if (argc < 3) {
***************
*** 128,150 ****
}
! /* Read credentials from stdin; user and passwd should each be on a line
* user may not include spaces. FIXME: password may not include
* spaces either, currently.
*/
! int readcredentials(user, passwd, n)
char *user;
char *passwd;
! int n;
{
! int result;
! /* we limit credentials to 100 characters in the scanf string.
! make sure we were passed big enough buffers (including room for NUL) */
! if (n <= 100) return 0;
! result = scanf("%100s%100s", user, passwd);
! if (result == EOF || result < 2) return 0;
! return 1;
}
#define CONFIGFILE "/etc/squirrelmail/config.php"
int readimapserver(server, serverlen)
char *server;
--- 123,179 ----
}
!
! /*
! * Read credentials from stdin; user and passwd should each be on a line
* user may not include spaces. FIXME: password may not include
* spaces either, currently.
+ *
+ * Parameters:
+ * user - OUT. The buffer is filled with username read from stdin.
+ * passwd - OUT. The buffer is filled with password read from stdin.
+ * buflen - IN. The buffer size for both buffers.
+ * Returns:
+ * ERR_OK if the credentials were read successfully, non-zero error code
+ * if not.
*/
! int readcredentials(user, passwd, buflen)
char *user;
char *passwd;
! int buflen;
{
! int n;
! if (fgets(user, buflen, stdin) == NULL)
! return ERR_NEED_CREDENTIALS;
! n = strlen(user);
! if (n < 2)
! return ERR_NEED_CREDENTIALS;
! if (user[n-1] == '\n')
! user[n-1] = '\0'; /* remove \n */
!
! if (fgets(passwd, buflen, stdin) == NULL)
! return ERR_NEED_CREDENTIALS;
! n = strlen(passwd);
! if (n < 2)
! return ERR_NEED_CREDENTIALS;
! if (passwd[n-1] == '\n')
! passwd[n-1] = '\0'; /* remove \n */
!
! return ERR_OK;
}
+ #ifndef CONFIGFILE
#define CONFIGFILE "/etc/squirrelmail/config.php"
+ #endif
+
+ /*
+ * Reads IMAP server information from CONFIGFILE.
+ *
+ * Parameters:
+ * server - OUT. the servername read from config.php
+ * serverlen - IN. buffer size of the server buffer.
+ * Returns:
+ * ERR_OK if it found all the parameters, an error code if not.
+ */
+
int readimapserver(server, serverlen)
char *server;
***************
*** 153,167 ****
FILE *f;
char line[STR_MAX];
! int foundserver = 0;
! f = fopen(CONFIGFILE, "r");
! if (!f) return 0;
while (fgets(line, STR_MAX, f)) {
if (!foundserver)
foundserver = parsephpstring("$imapServerAddress", line, server, serverlen);
}
! return foundserver;
}
int finduidgid(user, uid, gid)
char *user;
--- 182,208 ----
FILE *f;
char line[STR_MAX];
! int err, foundserver = 0;
! err = trusted_open(&f, CONFIGFILE, "r");
! if (err) return err;
while (fgets(line, STR_MAX, f)) {
if (!foundserver)
foundserver = parsephpstring("$imapServerAddress", line, server, serverlen);
}
! return foundserver ? ERR_OK : ERR_CANT_READ_IMAP_SERVER;
}
+ /*
+ * Determines uid and gid given a "real" username. A UID or
+ * GID of 0 is considered invalid.
+ *
+ * Parameters:
+ * user - IN. A UNIX username.
+ * uid - OUT. The UID of the UNIX username.
+ * gid - OUT. The GID of the UNIX username.
+ * Returns:
+ * ERR_OK if it found a valid uid/gid, an error code if not
+ */
+
int finduidgid(user, uid, gid)
char *user;
***************
*** 172,181 ****
p = getpwnam(user);
! if (!p) return 0;
*uid = p->pw_uid;
*gid = p->pw_gid;
! return 1;
}
int parsephpstring(varname, line, dest, destlen)
char *varname;
--- 213,242 ----
p = getpwnam(user);
! if (!p) return ERR_BAD_UID_GID;
! if (p->pw_uid == 0 || p->pw_gid == 0) {
! /* refuse to allow root's uid/gid to be used */
! return ERR_USER_IS_ROOT;
! }
*uid = p->pw_uid;
*gid = p->pw_gid;
! return ERR_OK;
}
+ /*
+ * Looks for a given varname in a line of PHP code; if it is found, the
+ * code will try to parse out the value between quotes. This funtion is
+ * easily confused and when it returns 1 it means the variable was found,
+ * not necessarily that the string contents were successfully passed.
+ *
+ * Parameters:
+ * varname - IN. The PHP variable to search for. SHould include $
+ * line - IN. A line of text. May end with \n.
+ * dest - OUT. Where the string contents will be placed if there is a match.
+ * destlen - IN. Size of the dest buffer.
+ *
+ * Returns:
+ * 1 if the varname was found, 0 if not.
+ */
+
int parsephpstring(varname, line, dest, destlen)
char *varname;
***************
*** 214,218 ****
! int getrc(char* filter_file, char* temp_file, uid_t UID, gid_t GID)
{
int result;
--- 275,279 ----
! int getrc(char* filter_file)
{
int result;
***************
*** 221,236 ****
return inerror(ERR_BAD_RC_PATH);
}
! if (!validtmppath(temp_file)) {
! return inerror(ERR_BAD_TEMP_PATH);
! }
! result = copy_file(filter_file, temp_file);
! if (result) return result;
! chown(temp_file, UID, GID);
! return 0;
}
! int putrc(char* user, char* temp_file, char* filter_file)
{
- struct passwd* user_pass;
int result;
--- 282,292 ----
return inerror(ERR_BAD_RC_PATH);
}
!
! result = copy_file(filter_file, NULL, NULL, stdout);
! return result;
}
! int putrc(char* filter_file, uid_t uid, gid_t gid)
{
int result;
***************
*** 238,268 ****
return inerror(ERR_BAD_RC_PATH);
}
- if (!validtmppath(temp_file)) {
- return inerror(ERR_BAD_TEMP_PATH);
- }
! user_pass = getpwnam(user);
!
! if (result = copy_file(temp_file, filter_file)) {
return result;
}
! chown(filter_file, user_pass->pw_uid, user_pass->pw_gid);
chmod(filter_file, (S_IRUSR|S_IWUSR));
- unlink(temp_file);
return 0;
}
! int copy_file(char* old_file, char* new_file)
{
- FILE *infile, *outfile;
char buf[MAXLEN];
!
! if (!(infile=fopen(old_file,"r"))) {
! fprintf(stderr, "Could not open %s\n", old_file);
! return ERR_COPY_CANT_OPEN_SRC;
}
! if (!(outfile=fopen(new_file,"w"))) {
! fprintf(stderr, "Could not open %s\n", new_file);
! return ERR_COPY_CANT_OPEN_DEST;
}
--- 294,322 ----
return inerror(ERR_BAD_RC_PATH);
}
! result = copy_file(NULL, stdin, filter_file, NULL);
! if (result) {
return result;
}
! chown(filter_file, uid, gid);
chmod(filter_file, (S_IRUSR|S_IWUSR));
return 0;
}
! int copy_file(char* old_file, FILE* infile, char* new_file, FILE* outfile)
{
char buf[MAXLEN];
!
! if (old_file) {
! if (!(infile=fopen(old_file,"r"))) {
! fprintf(stderr, "Could not open %s\n", old_file);
! return ERR_COPY_CANT_OPEN_SRC;
! }
}
! if (new_file) {
! if (!(outfile=fopen(new_file,"w"))) {
! fprintf(stderr, "Could not open %s\n", new_file);
! return ERR_COPY_CANT_OPEN_DEST;
! }
}
***************
*** 270,275 ****
fputs(buf, outfile);
}
! fclose(outfile);
! fclose(infile);
return 0;
}
--- 324,329 ----
fputs(buf, outfile);
}
! if (old_file) fclose(outfile);
! if (new_file) fclose(infile);
return 0;
}
***************
*** 350,352 ****
--- 404,488 ----
}
+ #ifndef SERVERSIDEFILTERHOME
+ #define SERVERSIDEFILTERHOME "/usr/share/squirrelmail/plugins/serversidefilter/"
+ #endif
+ int readvirtualdomain(char *user, char *real_user, int buflen) {
+ char *domain;
+ FILE *f;
+ char line[STR_MAX];
+ char *colon, *s;
+ int err;
+
+ domain = strchr(user, '@');
+ if (domain == NULL) {
+ /* no at sign in username implies no virtual domain -- not necessarily correct */
+ strncpy(real_user, user, buflen);
+ return ERR_OK;
+ }
+ domain++;
+
+ /* find the first line with a colon that matches the domain up to the colon.
+ * copy the rest of the line (or up to another colon) into the real_user
+ * buffer.
+ */
+ err = trusted_open(&f, SERVERSIDEFILTERHOME "virtualdomains", "r");
+ if (err) return err;
+ s = NULL; /* if s is set we know the domain was found */
+ while (fgets(line, STR_MAX, f)) {
+ colon = strchr(line, ':');
+ if (!colon) continue;
+ *colon = '\0';
+ if (strcmp(domain, line)) continue;
+ s = colon + 1;
+ colon = strpbrk(s, ":\n");
+ if (colon) *colon = '\0';
+ strncpy(real_user, s, buflen);
+ break;
+ }
+ fclose(f);
+ if (s) return ERR_OK;
+
+ return ERR_CANT_FIND_VIRTUAL_DOMAIN;
+ }
+
+ /* open a file while verifying that it is sufficiently protected so that
+ * we can trust its contents. That means the file must be owned by root,
+ * and either not group readable or be in root's group. The same test is
+ * applied to all the files, all the way up the tree.
+ */
+ int trusted_open(FILE** f, char *filepath, char *mode) {
+ char curpath[STR_MAX];
+ int err;
+
+ strncpy(curpath, filepath, STR_MAX);
+ err = trusted_check(filepath, curpath);
+ if (err) return err;
+ *f = fopen(filepath, mode);
+ return ERR_OK;
+ }
+ int trusted_check(char *filepath, char *curpath) {
+ struct stat buf;
+ char *ix = NULL;
+
+ do {
+ if (stat(filepath, &buf))
+ eperror(filepath);
+ if (buf.st_mode & S_IWOTH)
+ return trusted_error("writable by others", curpath, filepath);
+ if ((buf.st_mode & S_IWGRP) && (buf.st_gid != 0))
+ return trusted_error("writable by non-root group", curpath, filepath);
+ if ((buf.st_mode & S_IWUSR) && (buf.st_uid != 0))
+ return trusted_error("writable by non-root user", curpath, filepath);
+
+ /* find parent directory */
+ ix = rindex(curpath, '/');
+ if (!ix) return ERR_OK;
+ *ix = '\0';
+ } while (1);
+ }
+
+ int trusted_error(char *err, char *path, char *file) {
+ fprintf(stderr, "trust error on %s while checking %s\n %s\n", path, file, err);
+ return ERR_CANT_TRUST_FILE;
+ }
|