|
From: <ton...@us...> - 2003-12-14 10:51:37
|
Update of /cvsroot/serverfilters/script
In directory sc8-pr-cvs1:/tmp/cvs-serv31087
Modified Files:
filtercmd.c
Added Files:
Makefile filtercmd.opts test.sh
Log Message:
Progress on filtercmd credential checking.
filtercmd now reads a username and password from stdin; uses the username
to drop priviledges; reads the IMAP server from a file; but does not yet
actually try log in to the server. Path checking is in place. More
file owner checking needs to be done.
--- NEW FILE: Makefile ---
all: filtercmd
filtercmd: filtercmd.c filtercmd.opts
gcc -o filtercmd filtercmd.c `cat filtercmd.opts`
chmod 4750 filtercmd
chown root:apache filtercmd
test: test.sh filtercmd
sh test.sh
--- NEW FILE: filtercmd.opts ---
-DRCCHECK1="/home/*/.procmailrc"
-DTMPCHECK1="/tmp/*"
--- NEW FILE: test.sh ---
(echo $USER; echo a_password) | ./filtercmd getrc /home/$USER/.procmailrc /tmp/test || echo "RESULT:" $?
Index: filtercmd.c
===================================================================
RCS file: /cvsroot/serverfilters/script/filtercmd.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** filtercmd.c 9 Dec 2003 19:01:28 -0000 1.2
--- filtercmd.c 13 Dec 2003 19:47:39 -0000 1.3
***************
*** 1,10 ****
/*
! how-to compile:
! # gcc -o filtercmd filtercmd.c; chmod 4750 filtercmd; chown root:apache filtercmd
! */
#define STR_MAX 1024
#define MAXLEN 1024
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
--- 1,13 ----
/*
! * filtercmd -- installs/reads filter files (.procmailrc, etc) for squirrelmail
! *
! */
#define STR_MAX 1024
#define MAXLEN 1024
+
+
#include <stdio.h>
+ #include <string.h>
#include <unistd.h>
#include <sys/types.h>
***************
*** 17,21 ****
--- 20,77 ----
int putrc(char*, char*, char*);
int copy_file(char*, char*);
+ int validrcpath(char*);
+ int validtmppath(char*);
+ int checkpath(char*, char*);
+ int validpath(char*, char**);
+
+ /* error definitions */
+ #define ERR_NO_RC_FILE 1
+ #define ERR_NO_CMD 2
+ #define ERR_USAGE 3
+ #define ERR_INVALID_COMMAND 4
+ #define ERR_USER_IS_ROOT 5
+ #define ERR_BAD_RC_PATH 6
+ #define ERR_BAD_TEMP_PATH 7
+ #define ERR_COPY_CANT_OPEN_SRC 8
+ #define ERR_COPY_CANT_OPEN_DEST 9
+ #define ERR_NEED_CREDENTIALS 10
+ #define ERR_CANT_READ_IMAP_SERVER 11
+ #define ERR_BAD_UID_GID 12
+ #define ERR_BAD_CREDENTIALS 13
+ static char *err_strings[] = {
+ /* non error (error index 0) */
+ "",
+
+ /* silent error -- rcexists false result */
+ "",
+
+ "You forgot to provide a command.\n",
+
+ /* placeholder - usage errors are expected to be printed directly */
+ "Usage error - consult filtercmd.c\n",
+
+ "Invalid command specified.\n",
+
+ /* this command will refuse to handles root's filter files */
+ "The root user cannot be edited for security reasons\n",
+
+ "rc file path fails checks\n",
+
+ "temp file path fails checks\n",
+
+ "Can't open source file\n",
+
+ "Can't open destination file\n",
+
+ "Credentials not passed correctly\n",
+
+ "Can't read imap server from configfile\n",
+
+ "Can't find uid/gid for user\n",
+
+ "Bad credentials\n",
+
+ };
int main(int argc, char *argv[]){
***************
*** 29,83 ****
char cmd[STR_MAX];
char user[STR_MAX];
char filter_file[STR_MAX];
char temp_file[STR_MAX];
uid_t UID;
gid_t GID;
! UID = getuid();
! GID = getgid();
!
! if((setuid(0)) < 0) eperror("setuid");
! if((setgid(3)) < 0) eperror("setgid");
! sprintf(cmd,"%s",argv[1]);
if(!strlen(cmd)){
! printf("You forgot to provide a command.\n");
! return 1;
} else {
if (!strcmp("getrc",cmd)) {
if (argc < 4) {
printf("Usage: filtercmd getrc filter_file temp_file\n");
! return 2;
}
! sprintf(filter_file, "%s", argv[2]);
! sprintf(temp_file, "%s", argv[3]);
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 3;
}
! sprintf(user, "%s", argv[2]);
if(!strcmp(user,"root") && !strcmp(user, "0")){
! printf("The file cannot have root ownership for security reasons.\n");
! return 6; //the root user cannot be edited for security reasons
}
! sprintf(temp_file, "%s", argv[3]);
! sprintf(filter_file, "%s", argv[4]);
return putrc(user, temp_file, filter_file);
} else if (!strcmp("rcexists",cmd)) {
if (argc < 3) {
printf("Usage: filtercmd rcexists filter_file\n");
! return 4;
}
! sprintf(filter_file, "%s", argv[2]);
return rcexists(filter_file);
} else if (argc > 1) {
! printf("Invalid command specified.\n");
! return 5;
} else {
printf("Usage: filtercmd [getrc|putrc|rcexists]\n");
! return 7;
}
}
--- 85,151 ----
char cmd[STR_MAX];
char user[STR_MAX];
+ char passwd[STR_MAX];
char filter_file[STR_MAX];
char temp_file[STR_MAX];
+ char imap_server[STR_MAX];
uid_t UID;
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 (!checkcredentials(imap_server, user, passwd)) {
! return inerror(ERR_BAD_CREDENTIALS);
! }
!
! strncpy(cmd,argv[1],STR_MAX);
if(!strlen(cmd)){
! return inerror(ERR_NO_CMD);
} 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) {
printf("Usage: filtercmd rcexists filter_file\n");
! return ERR_USAGE;
}
! strncpy(filter_file, argv[2], STR_MAX);
return rcexists(filter_file);
} else if (argc > 1) {
! return inerror(ERR_INVALID_COMMAND);
} else {
printf("Usage: filtercmd [getrc|putrc|rcexists]\n");
! return ERR_USAGE;
}
}
***************
*** 94,109 ****
Thiago Melo de Paula - th...@fa...
*/
! char str[50];
! sprintf(str,"filtercmd - %s",s);
perror(str);
exit(1);
}
int rcexists(char* filter_file)
{
FILE *filter;
if(!(filter=fopen(filter_file,"r"))){
! return 7;
} else {
fclose(filter);
--- 162,271 ----
Thiago Melo de Paula - th...@fa...
*/
! char str[STR_MAX];
! snprintf(str,STR_MAX,"filtercmd - %s",s);
perror(str);
exit(1);
}
+ int inerror(errnum)
+ int errnum;
+ {
+ fprintf(stderr, "%s", err_strings[errnum]);
+ return errnum;
+ }
+
+ /* 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;
+ int serverlen;
+ {
+ 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;
+ uid_t *uid;
+ gid_t *gid;
+ {
+ struct passwd *p;
+
+ p = getpwnam(user);
+ if (!p) return 0;
+ *uid = p->pw_uid;
+ *gid = p->pw_gid;
+ return 1;
+ }
+
+ int checkcredentials(imapserver, user, passwd)
+ char *imapserver;
+ char *user;
+ char *passwd;
+ {
+ /*DEBUG*/
+ printf("checkcredentials: imap://%s:%s@%s\n", user, passwd, imapserver);
+
+ /*FIXME*/
+ printf("WARNING: credentials not checked\n");
+ return 1;
+ }
+
+ int parsephpstring(varname, line, dest, destlen)
+ char *varname;
+ char *line;
+ char *dest;
+ int destlen;
+ {
+ 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;
+ }
+
int rcexists(char* filter_file)
{
FILE *filter;
+ if (!validrcpath(filter_file)) {
+ return inerror(ERR_BAD_RC_PATH);
+ }
+
if(!(filter=fopen(filter_file,"r"))){
! return ERR_NO_RC_FILE; /* silent */
} else {
fclose(filter);
***************
*** 115,119 ****
int getrc(char* filter_file, char* temp_file, uid_t UID, gid_t GID)
{
! copy_file(filter_file, temp_file);
chown(temp_file, UID, GID);
return 0;
--- 277,290 ----
int getrc(char* filter_file, char* temp_file, uid_t UID, gid_t GID)
{
! int result;
!
! if (!validrcpath(filter_file)) {
! 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;
***************
*** 123,130 ****
{
struct passwd* user_pass;
! user_pass = getpwnam(user);
! if (copy_file(temp_file, filter_file)) {
! return 10;
}
chown(filter_file, user_pass->pw_uid, user_pass->pw_gid);
--- 294,310 ----
{
struct passwd* user_pass;
! int result;
! if (!validrcpath(filter_file)) {
! 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);
***************
*** 140,149 ****
if (!(infile=fopen(old_file,"r"))) {
! printf("Could not open %s", old_file);
! return 8;
}
if (!(outfile=fopen(new_file,"w"))) {
! printf("Could not open %s", new_file);
! return 9;
}
--- 320,329 ----
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;
}
***************
*** 155,156 ****
--- 335,413 ----
return 0;
}
+
+ /* 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" (take spaces out)
+ *
+ * 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;
+ }
+
+
|