From: <ton...@us...> - 2004-02-22 21:30:57
|
Update of /cvsroot/serverfilters/script In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28324 Modified Files: filtercmd.c filtercmd.h test.sh Log Message: filtercmd no longer takes file paths as arguments; instead it takes symbolic names for the types of files it manipulates (eg "filter" "forward") and looks up the correct path in a secure configuration file (config.php in the serversidefilter directory). The configuration directives that control the file are $FILTER_FILE_PATH and $FORWARD_FILE_PATH. Index: filtercmd.c =================================================================== RCS file: /cvsroot/serverfilters/script/filtercmd.c,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** filtercmd.c 25 Dec 2003 02:08:32 -0000 1.6 --- filtercmd.c 22 Feb 2004 21:18:01 -0000 1.7 *************** *** 1,6 **** ! /* ! * filtercmd -- installs/reads filter files (.procmailrc, etc) for squirrelmail * */ #define STR_MAX 1024 #define MAXLEN 1024 --- 1,97 ---- ! /* NAME: ! * ! * filtercmd -- installs/reads filter files (.procmailrc, etc) for squirrelmail ! * ! * SYNOPSYS: ! * ! * filtercmd getrc rctype > temprcfile < credentials ! * filtercmd putrc rctype < credentials < temprcfile ! * filtercmd rcexists rctype < credentials ! * ! * DESCRIPTION: ! * ! * The filtercmd program allows an unpriviledged program ! * (squirrelmail) to work with users' mail filtering configuration ! * files. The format of the mail filtering configuration files is not ! * parsed in any way. This program only handles reading and writing ! * the configuration files. These general steps are followed by filtercmd: ! * - read in IMAP credentials. ! * - verify credentials (log in to IMAP server). ! * - determine file location of rc file. ! * - act upon rc file as directed by command (first argument) ! * ! * The getrc command will copy the rc file to standard output. ! * ! * The putrc command will read an rc file from standard input, after ! * reading the credentials, and replace the existing rcfile. Note: the use ! * of two input-redirections is intended to indicate that the ! * ! * The rcexists command will return a zero exit status if the rc file exists, ! * non-zero otherwise. ! * ! * CREDENTIALS ! * ! * Credentials are passed to standard input. The username and ! * password should be terminated with newline (\n) characters. No other ! * characters should be passed. ! * ! * The credentials are used to log in to an IMAP server. The server host ! * name and port is read from the squirrelmail configuration file. ! * ! * Authentication is performed using the c-client software from UW. ! * See checkcreds_cclient.c for more details. ! * ! * RC FILE LOCATIONS ! * ! * RC file locations are calculated from settings in the serversidefilter ! * configuration file. The settings can contain the following markers which ! * are be replaced with values calculated from the username. ! * [USERNAME] ! * text in username before an @ character. ! * ! * [DOMAIN] ! * text in username after an @ character. ! * ! * [DOMUSER] ! * virtualdomains file, with lines in format domain:user, ! * is consulted. The value is the "user" matching the domain ! * as described above. ! * ! * If there is no @ character in the username, [USERNAME] will be the entire ! * text of the username, [DOMAIN] will be blank, [DOMUSER] will be blank and the ! * virtualdomains file will not be consulted. If the domain is not found in the ! * virtualdomains file then [DOMUSER] will be blank. ! * ! * More than one type of RC file can be handled by this script. The RC file ! * types are: ! * forward (.qmail file, or .forward file) ! * filter (.procmailrc, or .mailfilter) ! * ! * The settings in the configuration file that control the locations are: ! * $FORWARD_FILE_PATH (for "foward" rc type) ! * $FILTER_FILE_PATH (for "filter" rc type) ! * ! * RC FILE OWNERSHIP ! * ! * The RC files will be owned by the user named by [DOMUSER], or [USERNAME] if the ! * [DOMUSER] is blank. ! * ! * CONFIGURATION FILES ! * ! * filtercmd reads three different configuration files: ! * squirrelmail/config.php ! * serversidefilter/config.php ! * serversidefilter/virtualdomains * + * Each of the configuration files must be owned by root. + * + * DIAGNOSTICS + * + * filtercmd will exit with a non-zero status if an error occurs. + * filtercmd will write text to standard error in the case of + * some errors. See filtercmd.h for details. + * */ + #define STR_MAX 1024 #define MAXLEN 1024 *************** *** 9,12 **** --- 100,111 ---- #define DEBUG + /* define this in filtercmd.opts */ + #ifndef CONFIGFILE + #define CONFIGFILE "/etc/squirrelmail/config.php" + #endif + #ifndef SERVERSIDEFILTERHOME + #define SERVERSIDEFILTERHOME "/usr/share/squirrelmail/plugins/serversidefilter/" + #endif + #include <stdio.h> #include <string.h> *************** *** 22,31 **** int putrc(char*, uid_t, gid_t); int copy_file(char*, FILE*, char*, FILE*); - int validrcpath(char*); - int validtmppath(char*); - int checkpath(char*, char*); - int validpath(char*, char**); int checkcredentials(char*, char*, char*); int main(int argc, char *argv[]){ /* --- 121,132 ---- int putrc(char*, uid_t, gid_t); int copy_file(char*, FILE*, char*, FILE*); int checkcredentials(char*, char*, char*); + + /* global variables -- used in path calculation code */ + char user[STR_MAX]; + char real_user[STR_MAX]; + char *domain; + int main(int argc, char *argv[]){ /* *************** *** 37,42 **** 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]; --- 138,141 ---- *************** *** 45,49 **** uid_t UID; gid_t GID; ! err = readcredentials(user, passwd, STR_MAX); if (err) return inerror(err); --- 144,148 ---- uid_t UID; gid_t GID; ! err = readcredentials(user, passwd, STR_MAX); if (err) return inerror(err); *************** *** 74,78 **** return ERR_USAGE; } ! strncpy(filter_file, argv[2], STR_MAX); return getrc(filter_file); } else if (!strcmp("putrc", cmd)) { --- 173,181 ---- return ERR_USAGE; } ! ! if (!findfilterfile(argv[2], filter_file, STR_MAX)) { ! return inerror(ERR_BAD_RC_PATH); ! } ! return getrc(filter_file); } else if (!strcmp("putrc", cmd)) { *************** *** 81,85 **** return ERR_USAGE; } ! strncpy(filter_file, argv[2], STR_MAX); return putrc(filter_file, UID, GID); } else if (!strcmp("rcexists",cmd)) { --- 184,191 ---- return ERR_USAGE; } ! if (!findfilterfile(argv[2], filter_file, STR_MAX)) { ! return inerror(ERR_BAD_RC_PATH); ! } ! return putrc(filter_file, UID, GID); } else if (!strcmp("rcexists",cmd)) { *************** *** 88,92 **** return ERR_USAGE; } ! strncpy(filter_file, argv[2], STR_MAX); return rcexists(filter_file); } else if (argc > 1) { --- 194,201 ---- return ERR_USAGE; } ! if (!findfilterfile(argv[2], filter_file, STR_MAX)) { ! return inerror(ERR_BAD_RC_PATH); ! } ! return rcexists(filter_file); } else if (argc > 1) { *************** *** 162,169 **** } - #ifndef CONFIGFILE - #define CONFIGFILE "/etc/squirrelmail/config.php" - #endif - /* * Reads IMAP server information from CONFIGFILE. --- 271,274 ---- *************** *** 180,194 **** int serverlen; { 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; } --- 285,321 ---- int serverlen; { + int foundserver; + foundserver = readconfigvar(CONFIGFILE, "$imapServerAddress", server, serverlen); + return foundserver ? ERR_OK : ERR_CANT_READ_IMAP_SERVER; + } + + /* + * Reads a setting from CONFIGFILE. + * + * Parameters: + * phpvar - IN. the name of the PHP variable in config.php to parse out. + * outbuf - OUT. the setting as read from config.php + * outbuflen - IN. buffer size of the outbuf buffer. + * Returns: + * 1 if it the parameter, 0 if not. + */ + + int readconfigvar(configfile, phpvar, outbuf, outbuflen) + char *phpvar; + char *outbuf; + int outbuflen; + { FILE *f; char line[STR_MAX]; ! int err, found = 0; ! err = trusted_open(&f, configfile, "r"); if (err) return err; while (fgets(line, STR_MAX, f)) { ! /*fprintf(stderr, "config: %s", line);*/ ! if (!found) ! found = parsephpstring(phpvar, line, outbuf, outbuflen); } ! return found; } *************** *** 246,259 **** { char *s; int n; ! s = strstr(line, varname); ! if (s == NULL) return 0; /* skip ahead to either ' or " */ ! s += strcspn(line, "\"'\0\n") + 1; n = strcspn(s, "\"'\0\n"); if (n > destlen) n = destlen; strncpy(dest, s, n); return 1; } --- 373,401 ---- { char *s; + char *commentpos; int n; ! s = strstr(line, varname); ! if (s == NULL) return 0; ! ! /* look for // comment marker */ ! commentpos = strstr(line, "//"); ! if (commentpos && commentpos < s) return 0; + #ifdef DEBUG + /*fprintf(stderr, "parsephpstring: varname=%s line=%s", varname, line);*/ + #endif + /* skip ahead to either ' or " */ ! s += strcspn(s, "\"'\0\n") + 1; n = strcspn(s, "\"'\0\n"); if (n > destlen) n = destlen; strncpy(dest, s, n); + dest[n] = '\0'; + + #ifdef DEBUG + /*fprintf(stderr, "parsephpstring -> %s\n", dest);*/ + #endif + return 1; } *************** *** 262,268 **** { FILE *filter; - if (!validrcpath(filter_file)) { - return inerror(ERR_BAD_RC_PATH); - } if(!(filter=fopen(filter_file,"r"))){ --- 404,407 ---- *************** *** 279,286 **** int result; - if (!validrcpath(filter_file)) { - return inerror(ERR_BAD_RC_PATH); - } - result = copy_file(filter_file, NULL, NULL, stdout); return result; --- 418,421 ---- *************** *** 291,298 **** int result; - if (!validrcpath(filter_file)) { - return inerror(ERR_BAD_RC_PATH); - } - result = copy_file(NULL, stdin, filter_file, NULL); if (result) { --- 426,429 ---- *************** *** 329,412 **** } ! /* Path checking code. To limit the files that this command will touch, ! * define RCHECK1,2,3 to be a path with a single '*', ! * e.g. "/home/ * /.procmailrc" (without the spaces) * ! * At least one check must pass for a given file to be touched. */ ! #ifndef RCCHECK1 ! #define RCCHECK1 "*" ! #endif ! #ifndef RCCHECK2 ! #define RCCHECK2 NULL ! #endif ! #ifndef RCCHECK3 ! #define RCCHECK3 NULL ! #endif ! static char *rcpathchecks[] = { ! RCCHECK1, ! RCCHECK2, ! RCCHECK3, ! NULL, ! }; ! #ifndef TMPCHECK1 ! #define TMPCHECK1 "*" ! #endif ! #ifndef TMPCHECK2 ! #define TMPCHECK2 NULL ! #endif ! #ifndef TMPCHECK3 ! #define TMPCHECK3 NULL ! #endif ! static char *tmppathchecks[] = { ! TMPCHECK1, ! TMPCHECK2, ! TMPCHECK3, ! NULL, ! }; ! int validrcpath(char* file) { ! return validpath(file, rcpathchecks); ! } ! int validtmppath(char* file) { ! return validpath(file, tmppathchecks); } ! int validpath(char *file, char **p) { ! for (; *p; p++) { ! if (checkpath(file, *p)) ! return 1; ! } ! return 0; ! } ! int checkpath(char* file, char* check) { ! char *starpos, *suffix; ! int filelen, starlen, minlen, suffixlen; ! ! starpos = strchr(check, '*'); ! if (starpos == NULL) ! starpos = strchr(check, '\0'); ! starlen = starpos - check; ! filelen = strlen(file); ! minlen = starlen < filelen ? starlen : filelen; ! suffix = starpos + 1; ! suffixlen = strlen(suffix); ! return filelen >= suffixlen \ ! && strncmp(file, check, minlen) == 0 \ ! && strcmp(file+(filelen-suffixlen), suffix) == 0; } - #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]; --- 460,552 ---- } ! /* Path calculation code. * ! * ! * Parameters: ! * filter_type - IN. One of "filter", "forward". ! * filter_file - OUT. The resulting calculated path. ! * buflen - IN. Size of the filter_file buffer. ! * ! * Returns: ! * ERR_OK if the file was calculated, an error message if not. */ + int findfilterfile(char *filter_type, char *filter_file, int buflen) { + int err; ! err = findfilterpath(filter_type, filter_file, buflen); ! if (err) return err; ! fprintf(stderr, "filter_file: %s\n", filter_file); ! /* TODO: these need to be replaced with global variable references */ ! replace(filter_file, buflen, "[USERNAME]", real_user); ! replace(filter_file, buflen, "[DOMAIN]", domain ? domain : ""); ! replace(filter_file, buflen, "[DOMUSER]", user); ! ! /* DEBUG */ ! fprintf(stderr, "filter_file: %s\n", filter_file); ! } ! int findfilterpath(char* filter_type, char* filter_file, int buflen) { ! char* phpvar; ! if (0 == strcmp(filter_type, "filter")) { ! phpvar = "$FILTER_FILE_PATH"; ! } else if (0 == strcmp(filter_type, "forward")) { ! phpvar = "$FORWARD_FILE_PATH"; ! } else { ! return ERR_BAD_RC_FILE_TYPE; ! } ! fprintf(stderr, "phpvar: %s\n", phpvar); ! return readconfigvar(SERVERSIDEFILTERHOME "/config.php", phpvar, filter_file, buflen) ! ? ERR_OK : ERR_NO_RC_FILE_PATH; } ! /* Alter buf so that any instances of old are replaced by new ! * ! * Returns count of instances replaced. ! * ! * This is not a very good replace routine -- should not start from beginning ! * each time, and should not recalculate so many string lengths. ! */ ! int replace(char* buf, int buflen, char* old, char* new) { ! int oldlen = strlen(old); ! int newlen = strlen(new); ! int bufstrlen = strlen(buf); ! char* bufend = buf + bufstrlen; ! /* if negative, the string in buf gets shorter with each replacement */ ! /* if positive, the string in buf gets longer with each replacement */ ! int lendiff = newlen - oldlen; ! char *oldpos = strstr(buf, old); ! if (oldlen == 0) ! /* bad parameter - cannot search for empty substring */ ! return 0; ! ! if (oldpos == NULL) ! /* substring not found */ ! return 0; ! if ((bufstrlen + lendiff) > buflen) { ! /* buffer not big enough -- bail out */ ! #ifdef DEBUG ! fprintf(stderr, "replace: buffer not big enough -- bailing out\n"); ! #endif ! ! return 0; ! } ! ! if (lendiff > 0) { ! memmove(oldpos+lendiff, oldpos, bufend-oldpos+1); ! } ! strncpy(oldpos, new, newlen); ! if (lendiff < 0) { ! memmove(oldpos+newlen, oldpos+oldlen, bufend-(oldpos+oldlen)+1); ! } ! return 1 + replace(buf, buflen, old, new); } int readvirtualdomain(char *user, char *real_user, int buflen) { FILE *f; char line[STR_MAX]; *************** *** 428,432 **** 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, ':'); --- 568,573 ---- 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, ':'); Index: filtercmd.h =================================================================== RCS file: /cvsroot/serverfilters/script/filtercmd.h,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** filtercmd.h 25 Dec 2003 02:09:03 -0000 1.2 --- filtercmd.h 22 Feb 2004 21:18:01 -0000 1.3 *************** *** 18,21 **** --- 18,23 ---- #define ERR_CANT_FIND_VIRTUAL_DOMAIN 15 #define ERR_CANT_TRUST_FILE 16 + #define ERR_BAD_RC_FILE_TYPE 17 + #define ERR_NO_RC_FILE_PATH 18 static char *err_strings[] = { *************** *** 58,60 **** --- 60,66 ---- "Can't trust config file -- make sure they are all owned by root\n", + "Bad RC file type\n", + + "No RC file path found\n", + }; Index: test.sh =================================================================== RCS file: /cvsroot/serverfilters/script/test.sh,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** test.sh 25 Dec 2003 02:11:45 -0000 1.3 --- test.sh 22 Feb 2004 21:18:01 -0000 1.4 *************** *** 1,6 **** ! (echo tony; echo somepassword) | ./filtercmd getrc /home/tony/.procmailrc > filter; echo "RESULT:" $? echo '# hello world ' >> filter ! (echo tony; echo somepassword; cat filter) | ./filtercmd putrc /home/tony/.procmailrc; echo "RESULT:" $? ! (echo to...@so...; echo somepassword) | ./filtercmd getrc /home/tony/.procmailrc /tmp/test; echo "RESULT:" $? ! ! --- 1,4 ---- ! (echo tony; echo somepassword) | ./filtercmd getrc filter > filter; echo "RESULT:" $? echo '# hello world ' >> filter ! (echo tony; echo somepassword; cat filter) | ./filtercmd putrc filter; echo "RESULT:" $? ! (echo to...@so...; echo somepassword) | ./filtercmd getrc filter /tmp/test; echo "RESULT:" $? |