Author: rmeggins
Update of /cvs/dirsec/adminserver/admserv/cgi-src40
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv17655/adminserver/admserv/cgi-src40
Modified Files:
Makefile ReadLog.c dsconfig.c help.c htmladmin.c listOldSrvs.c
security.c snmpconf.c snmpmctl.c statpingserv.c viewdata.c
Removed Files:
userinfo.c
Log Message:
Bug: 186280
Description: Close potential security vulnerabilities in CGI code
Reviewed by: Nathan and Noriko (Thanks!)
Fix Description: These address a variety of issues with our CGIs. The basic
strategy is - Don't Trust The User - any data passed in as a GET/POST parameter
is suspect. I mostly looked at parameters which are filenames or filename
components, but I also made sure that we don't try to dereference a null
parameter or similar things such as that. For filenames, I mostly just verified
that path components contain path valid characters (e.g. not things like ../ or
"" or potential attack strings), verify that the given filename exists in the
given directory using opendir/readdir instead of just relying on PR_Access
(which would report success on a path like
/opt/fedora-ds/alias/../../../etc/passwd), and some attacks which could be based
on using something like this:
PR_snprintf(buf, sizeof(buf), "%s/alias", pathfromuser);
If pathfromuser overflows buf, the /alias will not be appended and we could be
using some bogus path. I replaced most of these with PR_smprintf.
Platforms tested: RHEL4
Flag Day: no
Doc impact: no
QA impact: should be covered by regular nightly and manual testing
New Tests integrated into TET: none
Index: Makefile
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/Makefile,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- Makefile 21 Mar 2006 18:33:48 -0000 1.9
+++ Makefile 11 May 2006 14:29:30 -0000 1.10
@@ -63,7 +63,7 @@
RB_PROGS = admpw config dsconfig htmladmin listOldSrvs mergeConfig migrateConfig monreplication restartsrv sec-activate security $(SNMP_PROGS) stopsrv ugdsconfig viewdata viewlog
#Programs without Resource Bundles
-NO_RB_PROGS = statusping userinfo ReadLog statpingserv
+NO_RB_PROGS = statusping ReadLog statpingserv
#Target CGI programs
PROGS = $(NO_RB_PROGS) $(RB_PROGS)
Index: ReadLog.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/ReadLog.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- ReadLog.c 18 Aug 2005 18:59:03 -0000 1.4
+++ ReadLog.c 11 May 2006 14:29:30 -0000 1.5
@@ -210,7 +210,7 @@
if(!proceed)
{
- fprintf(stdout, "Status: 1\nErrorString: name=%s\n", name);
+ fprintf(stdout, "Status: 1\nErrorString: name=%s\n", name?name:"");
exit(1);
}
}
@@ -236,7 +236,7 @@
if(!proceed)
{
- fprintf(stdout, "Status: 1\nErrorString: name=%s\n", name);
+ fprintf(stdout, "Status: 1\nErrorString: name=%s\n", name?name:"");
exit(1);
}
}
@@ -245,7 +245,7 @@
if(!proceed)
{
- fprintf(stdout, "Status: 1\nErrorString: op=%s\n", operation);
+ fprintf(stdout, "Status: 1\nErrorString: op=%s\n", operation?operation:"");
exit(1);
}
Index: dsconfig.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/dsconfig.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- dsconfig.c 31 Mar 2006 22:58:20 -0000 1.5
+++ dsconfig.c 11 May 2006 14:29:30 -0000 1.6
@@ -284,6 +284,26 @@
}
}
+/* return true if all of the chars in s are valid chars for use in
+ file and directory names, and false otherwise. This means that
+ the string must begin with a letter or number, and must contain
+ letters, numbers, '-' and '_'.
+*/
+static int
+is_valid_path_string(const char *s)
+{
+ int ret = 0;
+ if (s) {
+ if (isalnum(*s)) {
+ ret = 1;
+ for(; ret && *s; ++s) {
+ ret = isalnum(*s) || (*s == '-') || (*s == '_');
+ }
+ }
+ }
+ return ret;
+}
+
/*
* Modify ldap url setting
*/
@@ -313,6 +333,9 @@
if (strcasecmp(ssl_s, "true") == 0) {
if(!alias)
rpt_err(INCORRECT_USAGE, i18nMsg(DBT_NO_CERTDB,"No certificate database specified for LDAP/SSL usage!"), NULL, NULL);
+ if (!is_valid_path_string(alias)) {
+ rpt_err(INCORRECT_USAGE, i18nMsg(DBT_NO_CERTDB,"Invalid alias prefix for certificate database specified for LDAP/SSL usage!"), NULL, NULL);
+ }
ssl = 1;
PR_snprintf(keyfile, sizeof(keyfile), "alias%c%s-key3.db",
FILE_PATHSEP,
Index: help.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/help.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- help.c 31 Mar 2006 22:58:20 -0000 1.6
+++ help.c 11 May 2006 14:29:30 -0000 1.7
@@ -134,7 +134,7 @@
}
(*name)[cnt] = strdup(t);
- (*val)[cnt++] = "";
+ (*val)[cnt++] = strdup("");
}
return (cnt);
@@ -243,11 +243,13 @@
in the server installation */
loc = strtok(strdup(localeList), ",");
while (1){
- safe_snprintf(path, sizeof(path), "%s%c%c%c", BASE_DIR, FILE_SEP, loc[0], loc[1]);
- if (dir_open(path)) {
-/* return only the first 2 characters of the language code e.g. return en for en-US */
- loc[2] = '\0';
- return loc;
+ if (loc) {
+ safe_snprintf(path, sizeof(path), "%s%c%c%c", BASE_DIR, FILE_SEP, loc[0], loc[1]);
+ if (dir_open(path)) {
+ /* return only the first 2 characters of the language code e.g. return en for en-US */
+ loc[2] = '\0';
+ return loc;
+ }
}
loc = strtok(NULL, ",");
if (!loc) {
@@ -414,6 +416,32 @@
return 0;
}
+/* given the name of a directory and the name of a file/directory in that parent
+ return true if the given file/directory exists */
+static int
+file_or_dir_exists(const char *parent, const char *name)
+{
+ SYS_DIR *dp;
+ SYS_DIRENT *d;
+ int ret = 0; /* default to false */
+
+ dp = dir_open(parent);
+ /* loop through all directory entries until we find the one that matches */
+ while (dp && name && !ret && (d = dir_read(dp))) {
+ const char *entname = dir_name(d);
+ /* exclude "." and ".." from scanning */
+ if (strcmp(entname, ".") && strcmp(entname, "..")) {
+ /* set ret to true if the name matches, which terminates the while loop */
+ ret = !strcmp(name, entname);
+ }
+ }
+ if (dp) {
+ dir_close(dp);
+ }
+
+ return ret;
+}
+
/* the standard help response handler */
static int
help(char *name[], char *val[], int cnt)
@@ -461,8 +489,8 @@
if (debugPrintout)
{
- printf( "Product: %s<P>\n", product );
- printf( "Token: %s<P>\n", token );
+ printf( "Product: %s<P>\n", product?product:"" );
+ printf( "Token: %s<P>\n", token?token:"" );
}
/* Newer clients can specify a token map file */
@@ -477,8 +505,36 @@
printf( "Map file parameter: %s<P>\n", mapfile );
}
+ /* first, see if locale directory exists in its parent */
+ safe_snprintf(path, sizeof(path), "%s", BASE_DIR);
+ if (!file_or_dir_exists(path, locale)) {
+ if (debugPrintout) {
+ printf( "No help files for locale [%s]<P>\n", locale?locale:"");
+ fflush(stdout);
+ }
+ return error_exit("Failed to open help for locale.");
+ }
+ /* ok, locale directory is good, check product directory */
+ safe_snprintf(path, sizeof(path), "%s%c%s", BASE_DIR, FILE_SEP, locale);
+ if (!file_or_dir_exists(path, product)) {
+ if (debugPrintout) {
+ printf( "No help files for product [%s] in locale [%s]<P>\n", product?product:"", locale);
+ fflush(stdout);
+ }
+ return error_exit("Failed to open help for given product.");
+ }
+ /* Ok, product directory exists, check for the mapfile */
+ safe_snprintf(path, sizeof(path), "%s%c%s%c%s", BASE_DIR, FILE_SEP, locale,
+ FILE_SEP, product);
+ if (!file_or_dir_exists(path, mapfile)) {
+ if (debugPrintout) {
+ printf( "No map file [%s] for product [%s] in locale [%s]<P>\n", mapfile?mapfile:"", product, locale);
+ fflush(stdout);
+ }
+ return error_exit("Failed to open help for given product.");
+ }
safe_snprintf(path, sizeof(path), "%s%c%s%c%s%c%s", BASE_DIR, FILE_SEP, locale,
- FILE_SEP, product, FILE_SEP, mapfile);
+ FILE_SEP, product?product:"", FILE_SEP, mapfile);
if (debugPrintout)
{
printf( "Opening map file: %s<P>\n", path );
@@ -496,7 +552,7 @@
/* translate token */
/* match the token from the appropriate token.map file */
- while (fgets(path, PATH_LENGTH, tokenfile))
+ while (token && fgets(path, PATH_LENGTH, tokenfile))
{
char *p, *q;
@@ -530,7 +586,7 @@
{
if (debugPrintout)
{
- printf( "Failed to translate the token: %\n<BR>\n", token );
+ printf( "Failed to translate the token: %\n<BR>\n", token?token:"" );
fflush( stdout );
}
return error_exit("unable to translate the token");
Index: htmladmin.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/htmladmin.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- htmladmin.c 31 Mar 2006 22:58:20 -0000 1.6
+++ htmladmin.c 11 May 2006 14:29:30 -0000 1.7
@@ -186,6 +186,96 @@
#define SERVER_PING_RATE 5
+/* stolen from ldapserver util.c - need to escape values that may go into
+ ldap search filters */
+#define UTIL_ESCAPE_NONE 0
+#define UTIL_ESCAPE_HEX 1
+#define UTIL_ESCAPE_BACKSLASH 2
+
+static int special_filter(unsigned char c)
+{
+ /*
+ * Escape all non-printing chars and double-quotes in addition
+ * to those required by RFC 2254
+ */
+ return (c < 32 ||
+ c > 126 ||
+ c == '*' ||
+ c == '(' ||
+ c == ')' ||
+ c == '\\' ||
+ c == '"') ? UTIL_ESCAPE_HEX : UTIL_ESCAPE_NONE;
+}
+
+static const char*
+do_escape_string (
+ const char* str,
+ int len, /* -1 means str is nul-terminated */
+ char buf[BIG_LINE],
+ int (*special)(unsigned char)
+)
+{
+ const char* s;
+ const char* last;
+ int esc;
+
+ if (str == NULL) {
+ *buf = '\0';
+ return buf;
+ }
+
+ if (len == -1) len = strlen (str);
+ if (len == 0) return str;
+
+ last = str + len - 1;
+ for (s = str; s <= last; ++s) {
+ if ( (esc = (*special)((unsigned char)*s))) {
+ const char* first = str;
+ char* bufNext = buf;
+ int bufSpace = BIG_LINE - 4;
+ while (1) {
+ if (bufSpace < (s - first)) s = first + bufSpace - 1;
+ if (s > first) {
+ memcpy (bufNext, first, s - first);
+ bufNext += (s - first);
+ bufSpace -= (s - first);
+ }
+ if (s > last) {
+ break;
+ }
+ do {
+ *bufNext++ = '\\'; --bufSpace;
+ if (bufSpace < 2) {
+ memcpy (bufNext, "..", 2);
+ bufNext += 2;
+ goto bail;
+ }
+ if (esc == UTIL_ESCAPE_BACKSLASH) {
+ *bufNext++ = *s; --bufSpace;
+ } else { /* UTIL_ESCAPE_HEX */
+ sprintf (bufNext, "%02x", (unsigned)*(unsigned char*)s);
+ bufNext += 2; bufSpace -= 2;
+ }
+ } while (++s <= last &&
+ (esc = (*special)((unsigned char)*s)));
+ if (s > last) break;
+ first = s;
+ while ( (esc = (*special)((unsigned char)*s)) == UTIL_ESCAPE_NONE && s <= last) ++s;
+ }
+ bail:
+ *bufNext = '\0';
+ return buf;
+ }
+ }
+ return str;
+}
+
+const char*
+escape_filter_value(const char* str, int len, char buf[BIG_LINE])
+{
+ return do_escape_string(str,len,buf,special_filter);
+}
+
/*
* Get bind DN and bind PW info.
*/
@@ -308,6 +398,10 @@
group = strtok(sie, ",");
group = strtok(NULL, ",");
group = strtok(NULL, "\0");
+ if (!group) { /* invalid sie */
+ return NULL;
+ }
+
while(*group == ' ')
group++; /* eliminate spaces */
@@ -321,6 +415,9 @@
return NULL;
entry = ldap_first_entry(server, result);
+ if (!entry) {
+ return NULL;
+ }
if((vals = ldap_get_values(server, entry, ADMIN_HOST)) != NULL) {
host = strdup(vals[0]);
@@ -343,6 +440,9 @@
return NULL;
entry = ldap_first_entry(server, result);
+ if (!entry) {
+ return NULL;
+ }
/*
* Now search the SIE's configuration object to get the port and the security status.
@@ -353,6 +453,9 @@
return NULL;
entry = ldap_first_entry(server, result);
+ if (!entry) {
+ return NULL;
+ }
if((vals = ldap_get_values(server, entry, ADMINCONF_PORT)) != NULL) {
port = strdup(vals[0]);
@@ -407,40 +510,6 @@
if(*host && *port)
return 1;
- if(strstr(sie, "Messaging")) {
- /* Messaging special case - get ports for IMAP, POP and SMTP */
- int count;
- char *service_filters[3];
-
- service_filters[0] = strdup("(objectclass=nsmsgcfgimap)");
- service_filters[1] = strdup("(objectclass=nsmsgcfgpop)");
- service_filters[2] = strdup("(objectclass=nsmsgcfgmta)");
-
- for(count=0; count < 3; count++) {
- if((ldapError = ldap_search_s(server, sie, LDAP_SCOPE_SUBTREE,
- service_filters[count], NULL, 0, &result)) != LDAP_SUCCESS)
- return 0;
-
- entry = ldap_first_entry(server, result);
- if((vals = ldap_get_values(server, entry, MSGCONF_PORT)) != NULL) {
-
- if(!*port) {
- *port = (int *)malloc(3*sizeof(int));
- (*port)[0] = 0;
- (*port)[1] = 0;
- (*port)[2] = 0;
- }
- (*port)[count] = atoi(vals[0]);
- ldap_value_free(vals);
- }
- }
-
- if(*host && *port && (*port)[0] > 0 && (*port)[1] > 0 && (*port)[2] > 0)
- return 1;
- else
- return 0;
- }
-
PR_snprintf(sie_conf, BIG_LINE, "cn=configuration, %s",
sie);
@@ -622,6 +691,7 @@
char **vals;
char dn[BIG_LINE];
char filter[BIG_LINE];
+ char escaped_filter[BIG_LINE];
char *ptr, *ptr2, *ptr3;
LDAPMessage *result;
@@ -646,9 +716,12 @@
PR_snprintf(dn, sizeof(dn), "ou=\"%s\", ou=UserPreferences, %s", binddn, ptr3);
PR_snprintf(filter, sizeof(filter), "(&(objectclass=nscustomview)(nsdisplayname=%s))", view);
+ /* need to escape the filter value because the view value was given by the user and may
+ contain values like = () etc. */
+ escape_filter_value(filter, -1, escaped_filter);
ldapError = ldap_search_s(server, dn, LDAP_SCOPE_SUBTREE,
- filter, NULL, 0, &result);
+ escaped_filter, NULL, 0, &result);
if(ldapError != LDAP_SUCCESS)
/* fatal error, bail */
@@ -661,7 +734,7 @@
PR_snprintf(dn, sizeof(dn), "ou=Global Preferences, %s", ptr3);
ldapError = ldap_search_s(server, dn, LDAP_SCOPE_SUBTREE,
- filter, NULL, 0, &result);
+ escaped_filter, NULL, 0, &result);
if(ldapError != LDAP_SUCCESS)
/* fatal error, bail */
return NULL;
@@ -750,15 +823,13 @@
int is_local_admin(char *host, int port) {
- char *localhost = (char *)malloc(NBUF_SIZE);
+ char localhost[NBUF_SIZE];
int localport, is_local=0;
char *endptr;
FILE *f;
- char *admConf = (char *)malloc(strlen(getenv("ADMSERV_ROOT"))+ /*<sr>/admin-serv/config*/
- strlen("/adm.conf")+1);
-
- PR_snprintf(admConf, sizeof(admConf), "%s%cadm.conf", getenv("ADMSERV_ROOT"), FILE_PATHSEP);
+ char *admConf = PR_smprintf("%s%cadm.conf", getenv("ADMSERV_ROOT"), FILE_PATHSEP);
+ localhost[0] = 0;
/* get host name(FQDN) and port number from config file */
f = fopen(admConf, "r");
@@ -770,18 +841,17 @@
localport = strtol(strstr(line, " "), &endptr, 10);
}
if (strstr(line,"host:") == line) {
- PR_snprintf(localhost, NBUF_SIZE, "%s", (strstr(line, " ")+1));
+ PR_snprintf(localhost, sizeof(localhost), "%s", (strstr(line, " ")+1));
}
lineno++;
}
free(line);
+ fclose(f);
}
- fclose(f);
is_local = ((localport == port) && !strcmp(localhost, host));
- free(admConf);
- free(localhost);
+ PR_smprintf_free(admConf);
return is_local;
}
@@ -794,10 +864,7 @@
int rate = 300;
FILE *f;
- char *admConf = (char *)malloc(strlen(getenv("ADMSERV_ROOT"))+ /*<sr>/admin-serv/config*/
- strlen("/adm.conf")+1);
-
- PR_snprintf(admConf, sizeof(admConf), "%s%cadm.conf", getenv("ADMSERV_ROOT"), FILE_PATHSEP);
+ char *admConf = PR_smprintf("%s%cadm.conf", getenv("ADMSERV_ROOT"), FILE_PATHSEP);
/* get host name(FQDN) and port number from config file */
f = fopen(admConf, "r");
@@ -811,10 +878,10 @@
lineno++;
}
free(line);
+ fclose(f);
}
- fclose(f);
- free(admConf);
+ PR_smprintf_free(admConf);
return rate;
}
@@ -827,10 +894,7 @@
int rate = 60;
FILE *f;
- char *admConf = (char *)malloc(strlen(getenv("ADMSERV_ROOT"))+ /*<sr>/admin-serv/config*/
- strlen("/adm.conf")+1);
-
- PR_snprintf(admConf, sizeof(admConf), "%s%cadm.conf", getenv("ADMSERV_ROOT"), FILE_PATHSEP);
+ char *admConf = PR_smprintf("%s%cadm.conf", getenv("ADMSERV_ROOT"), FILE_PATHSEP);
/* get host name(FQDN) and port number from config file */
f = fopen(admConf, "r");
@@ -844,10 +908,10 @@
lineno++;
}
free(line);
+ fclose(f);
}
- fclose(f);
- free(admConf);
+ PR_smprintf_free(admConf);
return rate;
}
@@ -986,8 +1050,7 @@
int output_topology(AdmldapInfo ldapInfo,
char *binddn,
char *bindpw,
- char *view,
- char *op) {
+ char *view) {
char *host = admldapGetHost(ldapInfo);
@@ -1751,7 +1814,7 @@
fprintf(stdout, getResourceString(DBT_MAIN_PAGE_HEADER));
- if(!strcmp(operation, "index")) {
+ if(operation && !strcmp(operation, "index")) {
/*
* Load the frames.
@@ -1762,12 +1825,12 @@
fprintf(stdout, getResourceString(DBT_MAIN_FRAME_FOOTER));
}
- else if(!strcmp(operation, "empty")) {
+ else if(operation && !strcmp(operation, "empty")) {
/* Message frame */
fprintf(stdout, getResourceString(DBT_MAIN_MESSAGE_FRAME));
}
- else if(!strcmp(operation, "topframepaint")) {
+ else if(operation && !strcmp(operation, "topframepaint")) {
FILE *html = open_html_file(MY_PAGE);
while(next_html_line(html, line)) {
if(parse_line(line, NULL)) {
@@ -1775,14 +1838,14 @@
}
}
}
- else if(!strcmp(operation, "framepaint")) {
+ else if(operation && !strcmp(operation, "framepaint")) {
fprintf(stdout, getResourceString(DBT_MAIN_FRAMESET_HEADER));
fprintf(stdout, "%s", view ? viewparam : "");
fprintf(stdout, getResourceString(DBT_MAIN_FRAMESET_BODY));
fprintf(stdout, "%s", view ? viewparam : "");
fprintf(stdout, getResourceString(DBT_MAIN_FRAMESET_FOOTER));
}
- else if(!strcmp(operation, "viewselect")) {
+ else if(operation && !strcmp(operation, "viewselect")) {
/*
* Load the custom view frame.
*/
@@ -1842,7 +1905,7 @@
if(!get_bindinfo(&binddn, &bindpw))
exit(0);
- if(!strcmp(operation, "serveractivate")) {
+ if(operation && !strcmp(operation, "serveractivate")) {
/* first turn on or off the server, then load the topology. */
int rv;
@@ -1859,30 +1922,12 @@
char *sie;
int count, max_count;
- if(strstr(object, "Messaging")) {
- /* we're at the service dn - go up to the messaging SIE */
- if(strstr(object, "imap"))
-
- service = getResourceString(DBT_MAIN_IMAP);
- else if(strstr(object, "pop"))
-
- service = getResourceString(DBT_MAIN_POP);
- else if(strstr(object, "smtp"))
-
- service = getResourceString(DBT_MAIN_SMTP);
- else
- /* POP by default */
-
- service = getResourceString(DBT_MAIN_POP);
- sie = strtok(object, ",");
- sie = strtok(NULL, ",");
- sie = strtok(NULL, ",");
- sie = strtok(NULL, "\0");
- while(*sie == ' ')
- sie++;
- }
- else
+ if (object) {
sie = strdup(object);
+ } else {
+ sie = NULL;
+ goto output_topology;
+ }
server = server_bind(admldapGetHost(ldapInfo),
admldapGetPort(ldapInfo),
@@ -1907,19 +1952,7 @@
if(!get_host_and_port(server, sie, sie_entry, &host, &ports))
goto output_topology;
- if(service) {
- if(!strcmp(service, "imap"))
- active_port = ports[0];
- else if(!strcmp(service, "pop"))
- active_port = ports[1];
- else if(!strcmp(service, "smtp"))
- active_port = ports[2];
- else
- /* POP by default */
- active_port = ports[1];
- }
- else
- active_port = ports[0];
+ active_port = ports[0];
if((admin_url = get_admin_url(server, sie)) == NULL)
goto output_topology;
@@ -1968,8 +2001,7 @@
rv = output_topology(ldapInfo,
binddn,
bindpw,
- view,
- operation);
+ view);
if(rv == -1) {
fprintf(stdout, getResourceString(DBT_MAIN_LDAP_ERROR));
Index: listOldSrvs.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/listOldSrvs.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- listOldSrvs.c 31 Mar 2006 22:58:20 -0000 1.5
+++ listOldSrvs.c 11 May 2006 14:29:30 -0000 1.6
@@ -33,10 +33,17 @@
#include "prio.h"
#include "plstr.h"
#include "prmem.h"
+#include "prprf.h"
#include "libadminutil/resource.h"
#include "libadminutil/distadm.h"
#include "libadminutil/admutil.h"
#include "libadminutil/resource.h"
+# define SYS_DIR PRDir
+# define SYS_DIRENT PRDirEntry
+# define dir_open PR_OpenDir
+# define dir_read(d) PR_ReadDir(d, PR_SKIP_BOTH)
+# define dir_close PR_CloseDir
+# define dir_name(de) (de->name)
#define RESOURCE_FILE "listOldSrvs"
@@ -121,6 +128,32 @@
return 1;
}
+/* given the name of a directory and the name of a file/directory in that parent
+ return true if the given file/directory exists */
+static int
+file_or_dir_exists(const char *parent, const char *name)
+{
+ SYS_DIR *dp;
+ SYS_DIRENT *d;
+ int ret = 0; /* default to false */
+
+ dp = dir_open(parent);
+ /* loop through all directory entries until we find the one that matches */
+ while (dp && name && !ret && (d = dir_read(dp))) {
+ const char *entname = dir_name(d);
+ /* exclude "." and ".." from scanning */
+ if (strcmp(entname, ".") && strcmp(entname, "..")) {
+ /* set ret to true if the name matches, which terminates the while loop */
+ ret = !strcmp(name, entname);
+ }
+ }
+ if (dp) {
+ dir_close(dp);
+ }
+
+ return ret;
+}
+
char**
get_server_list(char* oldServerRoot, char* errorInfo, size_t errorSize) {
@@ -129,30 +162,55 @@
FILE *fstream;
int result, num = 0, i, match;
char **servers = NULL;
- char fileName[256];
+ char *fileName;
const char *errMsg = NULL;
if (!oldServerRoot) return 0;
- PR_snprintf(fileName, sizeof(fileName), "%s/admin-serv/config/%s", oldServerRoot, "servers.lst" );
+ /* since oldServerRoot is passed in from a (potentially malicious) user, we cannot
+ assume it will fit into a buffer of MAX_PATH/PATH_MAX size e.g. what if the
+ value were something like /etc/../etc/../etc/../ ....... ../etc/passwd which
+ was exactly 255 bytes long? If we just did an PR_snprintf of this string into
+ a buffer of size 256, the final fileName value would end up being /etc/passwd */
+ /* first, construct the base name from the given server root */
+ fileName = PR_smprintf(oldServerRoot); /* essentially, just a strdup */
+ if (!fileName) {
+ goto errorreturn;
+ }
+ /* next, see if the path has an "admin-serv" sub directory - also tests if fileName is NULL */
+ if (file_or_dir_exists(fileName, "admin-serv")) {
+ /* ok, admin-serv subdir exists - append that to fileName and look for config */
+ fileName = PR_sprintf_append(fileName, "/admin-serv");
+ /* next, see if the path has an "config" sub directory - also tests if fileName is NULL */
+ if (!fileName || !file_or_dir_exists(fileName, "config")) {
+ goto errorreturn;
+ }
+ /* ok, config subdir exists - append that to fileName and look for servers.lst */
+ fileName = PR_sprintf_append(fileName, "/config");
+ /* next, see if the path has an "servers.lst" file - also tests if fileName is NULL */
+ if (!fileName || !file_or_dir_exists(fileName, "servers.lst")) {
+ goto errorreturn;
+ }
+ /* ok, servers.lst exists, append it */
+ } else if (file_or_dir_exists(fileName, "admserv")) {
+ /* ok, admserv subdir exists - append that to fileName and look for servers.lst */
+ fileName = PR_sprintf_append(fileName, "/admserv");
+ /* next, see if the path has an "servers.lst" file - also tests if fileName is NULL */
+ if (!fileName || !file_or_dir_exists(fileName, "servers.lst")) {
+ goto errorreturn;
+ }
+ } else {
+ goto errorreturn;
+ }
+ /* ok, servers.lst exists, append it */
+ fileName = PR_sprintf_append(fileName, "/servers.lst");
- if(!(fstream = fopen(fileName, "r"))) {
- /* Not a 3x server Root - try for 2x */
- PR_snprintf(fileName, sizeof(fileName), "%s/admserv/%s", oldServerRoot, "servers.lst" );
- if(!(fstream = fopen(fileName, "r"))) {
-
- if (i18nResource &&
- (errMsg = res_getstring(i18nResource,
- DBT_ERROR_OPEN_FILE,
- acceptLanguage)))
- PR_snprintf(errorInfo, errorSize, errMsg, fileName);
- else
- PR_snprintf(errorInfo, errorSize, "Error open file: %s", fileName);
- return 0;
- }
+ if(!fileName || !(fstream = fopen(fileName, "r"))) {
+ goto errorreturn;
}
if (!(result = readServersList(oldServerRoot, fstream, fileName, errorInfo, errorSize))) {
+ PR_smprintf_free(fileName);
return NULL;
}
@@ -187,6 +245,21 @@
}
PR_CloseDir(sr);
return servers;
+
+errorreturn:
+ if (fileName) {
+ if (i18nResource &&
+ (errMsg = res_getstring(i18nResource,
+ DBT_ERROR_OPEN_FILE,
+ acceptLanguage))) {
+ PR_snprintf(errorInfo, errorSize, errMsg, fileName);
+ } else {
+ PR_snprintf(errorInfo, errorSize, "Error open file: %s", fileName);
+ }
+ PR_smprintf_free(fileName);
+ }
+
+ return NULL;
}
@@ -200,7 +273,7 @@
int err;
int *errp = &err;
char *oldSR = 0;
- char **inputs = 0, **server_list = 0;
+ char **server_list = 0;
char *operation = 0;
char *qs = 0;
char *nameptr, *valptr, *val;
@@ -262,8 +335,6 @@
rpt_err(INCORRECT_USAGE, error_info, NULL, NULL);
}
- inputs = get_input_ptr();
-
oldSR = get_cgi_var("oldServerRoot", NULL, NULL);
if (!oldSR) {
Index: security.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/security.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- security.c 31 Mar 2006 22:58:20 -0000 1.7
+++ security.c 11 May 2006 14:29:30 -0000 1.8
@@ -241,6 +241,163 @@
extra);
}
+static int
+copyFile(const char *srcname, const char *destname)
+{
+ PRFileDesc *srcp = NULL, *destp = NULL;
+ PRInt32 bytes;
+ char buf[BUFSIZ];
+ int ret = 0;
+
+ srcp = PR_Open(srcname, PR_RDONLY, 0);
+ if(!srcp) {
+ rpt_err(APP_ERROR, "Cannot open src file for copy!", NULL, NULL);
+ goto cleanup_and_return;
+ }
+ destp = PR_Open(destname, PR_RDWR|PR_CREATE_FILE, PR_IRUSR|PR_IWUSR);
+ if(!destp) {
+ rpt_err(APP_ERROR, "Cannot open dest file for copy!", NULL, NULL);
+ goto cleanup_and_return;
+ }
+ while (0 < (bytes = PR_Read(srcp, buf, sizeof(buf)))) {
+ PRInt32 remaining = bytes;
+ PRInt32 byteswritten = 0;
+ while (((byteswritten = PR_Write(destp, buf+byteswritten, remaining)) != remaining) &&
+ (byteswritten > 0)) {
+ remaining -= byteswritten;
+ }
+ if (byteswritten < 0) {
+ rpt_err(APP_ERROR, "Cannot write data to dest file for file copy!", NULL, NULL);
+ goto cleanup_and_return;
+ }
+ }
+ if (bytes < 0) {
+ rpt_err(APP_ERROR, "Cannot read data from src for file copy!", NULL, NULL);
+ } else if (bytes == 0) {
+ ret = 1; /* success */
+ }
+
+cleanup_and_return:
+ if (destp) {
+ PR_Close(destp);
+ }
+ if (srcp) {
+ PR_Close(srcp);
+ }
+
+ return ret;
+}
+
+/* return true if all of the chars in s are valid chars for use in
+ file and directory names, and false otherwise. This means that
+ the string must begin with a letter or number, and must contain
+ letters, numbers, '-' and '_'.
+*/
+static int
+is_valid_path_string(const char *s)
+{
+ int ret = 0;
+ if (s) {
+ if (isalnum(*s)) {
+ ret = 1;
+ for(; ret && *s; ++s) {
+ ret = isalnum(*s) || (*s == '-') || (*s == '_');
+ }
+ }
+ }
+ return ret;
+}
+
+/* try various ways to determine if the given name is a valid
+ file or directory - this value is passed in as a form
+ parameter, and our motto is "Don't trust the user!"
+ If the given filetype is directory, also check to see if the optional
+ given filename (may be NULL) is in the given directory
+*/
+static int
+verify_file_or_dir(
+ const char *name, /* name of file or directory to check */
+ PRFileType filetype, /* type of name */
+ const char *childname, /* optional child file/dir to check inside given parent name */
+ size_t childlen, /* only compare first childlen chars of childname - use -1 for entire string */
+ PRFileType childtype /* type of child */
+)
+{
+ int ret = 0;
+ PRFileInfo fileinfo;
+ /* first, just a simple access check */
+ PRStatus status = PR_GetFileInfo(name, &fileinfo);
+ ret = ((status == PR_SUCCESS) && (fileinfo.type == filetype));
+ if (ret) {
+ /* checks out ok - let's split it into the base name and the parent dir,
+ open the parent dir, and see if the base name exists in the parent dir
+ */
+ char *copy = PL_strdup(name);
+ size_t len = strlen(copy);
+ char *ptr = ©[len-1];
+ /* get the basename - a really bad name may look like
+ /path/foo/// or even ///////////////// */
+ for (; (ptr > copy) && (*ptr == '/'); --ptr) {
+ /* do nothing */
+ }
+ if ((ptr == copy) && (*ptr == '/')) {
+ /* bad - string consists of nothing but '/' */
+ ptr = NULL;
+ ret = 0;
+ } else {
+ PRDir *pdir;
+ PRDirEntry *pent;
+
+ ret = 0;
+ if (*ptr == '/') {
+ *ptr = 0; /* terminate the string at the first trailing '/' */
+ }
+ ptr = strrchr(copy, '/');
+ if (!ptr) {
+ ptr = copy;
+ copy = PL_strdup(".");
+ } else {
+ *ptr = 0;
+ ++ptr;
+ ptr = PL_strdup(ptr);
+ }
+ /* copy now points at the parent, ptr at the child */
+ if (pdir = PR_OpenDir(copy)) {
+ for(pent = PR_ReadDir(pdir, PR_SKIP_BOTH); pent && !ret;
+ pent = PR_ReadDir(pdir, PR_SKIP_BOTH)) {
+ ret = !strcmp(pent->name, ptr);
+ }
+ PR_CloseDir(pdir);
+ }
+ if (ret && childname && (filetype == PR_FILE_DIRECTORY)) {
+ ret = 0;
+ /* we've verified that name is a valid directory - see if
+ the given filename exists in that directory */
+ if (pdir = PR_OpenDir(name)) {
+ for(pent = PR_ReadDir(pdir, PR_SKIP_BOTH); pent && !ret;
+ pent = PR_ReadDir(pdir, PR_SKIP_BOTH)) {
+ if (childlen > 0) {
+ ret = !strncmp(pent->name, childname, childlen);
+ } else {
+ ret = !strcmp(pent->name, childname);
+ }
+ }
+ PR_CloseDir(pdir);
+ if (ret) {
+ /* child exists - check type */
+ char *fullname = PR_smprintf("%s%c%s", name, FILE_PATHSEP, childname);
+ status = PR_GetFileInfo(fullname, &fileinfo);
+ ret = ((status == PR_SUCCESS) && (fileinfo.type == childtype));
+ PR_smprintf_free(fullname);
+ }
+ }
+ }
+ }
+ PL_strfree(copy);
+ PL_strfree(ptr);
+ }
+ return ret;
+}
/*
** Convert a der-encoded integer to a hex printable string form
@@ -579,6 +736,9 @@
{
/* display crl or ckl */
+ if (!crl) {
+ return;
+ }
fprintf(stdout, "\t<NAME>%s</NAME>\n", constructNameDesc(&crl->crl.name));
if (detail) {
@@ -718,10 +878,24 @@
static void listCert(char* tokenName) {
/* int expired = 0; */
- PK11SlotInfo *slot = PK11_FindSlotByName(tokenName);
- char *internalTokenName = PK11_GetTokenName(PK11_GetInternalKeySlot());
CERTCertList *certList;
CERTCertListNode *cln;
+ PK11SlotInfo *slot = PK11_FindSlotByName(tokenName);
+ PK11SlotInfo *internal_slot;
+ char *internalTokenName;
+
+ if (!slot) {
+ errorRpt(GENERAL_FAILURE, getResourceString(DBT_TOKEN_NAME));
+ return;
+ }
+
+ internal_slot = PK11_GetInternalKeySlot();
+ if (!internal_slot) {
+ errorRpt(GENERAL_FAILURE, getResourceString(DBT_INIT_FAIL));
+ return;
+ }
+
+ internalTokenName = PK11_GetTokenName(internal_slot);
{
PK11SlotInfo *slot = PK11_GetInternalKeySlot();
@@ -1268,9 +1442,16 @@
PRBool keepCerts = PR_TRUE;
PRBool caOnly = PR_TRUE;
char *nickname = certname;
- int trustFlags = atoi(getParameter("trust_flag",getResourceString(DBT_TRUST)));
- int trustedCA = (trustFlags & CERTDB_TRUSTED_CA);
-
+ char *truststr = getParameter("trust_flag",getResourceString(DBT_TRUST));
+ int trustedCA;
+ char *endptr = NULL;
+ int trustflag = strtol(truststr, &endptr, 0);
+
+ if ((*truststr == '\0') || !endptr || (*endptr != '\0')) {
+ /* invalid trust flags */
+ errorRpt(GENERAL_FAILURE, getResourceString(DBT_TRUST_SET_FAIL));
+ }
+ trustedCA = (trustflag & CERTDB_TRUSTED_CA);
CERT_ImportCerts(certdb,(trustedCA ? certUsageSSLCA : certUsageAnyCA),
collectArgs->numcerts, &collectArgs->rawCerts,
&retCerts, keepCerts, caOnly, nickname);
@@ -1279,7 +1460,7 @@
errorRpt(GENERAL_FAILURE, getResourceString(DBT_INSTALL_FAIL));
}
- setTrust(processNullString(getMD5Fingerprint(retCerts[0])), trustFlags);
+ setTrust(processNullString(getMD5Fingerprint(retCerts[0])), trustflag);
}
}
@@ -1295,7 +1476,7 @@
slot= PK11_FindSlotByName(tokenName);
}
- if (PK11_NeedUserInit(slot) == PR_TRUE) {
+ if (slot && (PK11_NeedUserInit(slot) == PR_TRUE)) {
/*errorRpt(INCORRECT_USAGE, getResourceString(DBT_INVALID_CONFIRM_PWD));*/
rpt_success("TRUE");
} else {
@@ -1320,7 +1501,7 @@
}
- if (PK11_InitPin(slot, 0, keypwd) != SECSuccess) {
+ if (!slot || (PK11_InitPin(slot, 0, keypwd) != SECSuccess)) {
errorRpt(APP_ERROR, getResourceString(DBT_INIT_FAIL));
}
}
@@ -1352,7 +1533,7 @@
* Delete crl/krl
*/
static void deleteCRL(char* crlname, char* type) {
- int list_type = !PORT_Strcmp(type, "CKL")? SEC_KRL_TYPE : SEC_CRL_TYPE;
+ int list_type = (type && !PORT_Strcmp(type, "CKL"))? SEC_KRL_TYPE : SEC_CRL_TYPE;
CERTSignedCrl* crl = cmgFindCrlByName(certdb, crlname, list_type);
if (!crl) {
errorRpt(GENERAL_FAILURE, getResourceString(DBT_CRL_CKL_NOT_FOUND));
@@ -1373,7 +1554,12 @@
SECItem derCrl;
char msg[BIG_LINE];
- int list_type = !PORT_Strcmp(type, "CKL")? SEC_KRL_TYPE : SEC_CRL_TYPE;
+ int list_type = (type && !PORT_Strcmp(type, "CKL"))? SEC_KRL_TYPE : SEC_CRL_TYPE;
+ if (!verify_file_or_dir(filename, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
+ /* invalid file */
+ PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), filename);
+ errorRpt(FILE_ERROR, msg);
+ }
{/*try open the file*/
FILE *f;
@@ -1698,7 +1884,10 @@
dllname = get_cgi_var("dllname", NULL, NULL);
if (!PORT_Strcmp(op, "remove")) {
-
+ if (!dllname || !verify_file_or_dir(dllname, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
+ PR_snprintf(msg, sizeof(msg), getResourceString(DBT_MISSING_MODULE_NAME));
+ rpt_err(INCORRECT_USAGE, msg, NULL, NULL);
+ }
PR_snprintf(cmd, sizeof(cmd), "%s -dbdir %s -force -nocertdb -delete \"%s\" 2>&1",
binary,
database_dir,
@@ -1709,13 +1898,15 @@
filename = getParameter("filename",getResourceString(DBT_MISSING_FILE));
filetype = getParameter("format",getResourceString(DBT_MISSING_FORMAT));
- if(PR_Access(filename, PR_ACCESS_EXISTS) == PR_FAILURE) {
+ if((PR_Access(filename, PR_ACCESS_EXISTS) == PR_FAILURE) ||
+ !verify_file_or_dir(filename, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), filename);
rpt_err(FILE_ERROR, msg, NULL, NULL);
}
if((filetype && (!PORT_Strcmp(filetype, "dll"))) &&
- (!dllname || !PORT_Strcmp(dllname, ""))) {
+ (!dllname || !PORT_Strcmp(dllname, "") ||
+ !verify_file_or_dir(dllname, PR_FILE_FILE, NULL, 0, (PRFileType)0))) {
PR_snprintf(msg, sizeof(msg), getResourceString(DBT_MISSING_MODULE_NAME));
rpt_err(INCORRECT_USAGE, msg, NULL, NULL);
}
@@ -1840,18 +2031,20 @@
/* Makes a list of the aliases installed on machine. */
static void listAlias()
{
- char path[PATH_MAX];
+ char *path = NULL;
char *remstr;
char *keystr = "-key";
char **alist;
int x;
char * serverRoot = getParameter("old_server_root",getResourceString(DBT_OLD_SERVER_ROOT));
- PR_snprintf(path, sizeof(path), "%s%calias", serverRoot, FILE_PATHSEP);
- if (PR_FAILURE == PR_Access(path, PR_ACCESS_EXISTS)) {
+ /* see if serverRoot is legitimate, and also make sure it contains an "alias" directory */
+ if (!verify_file_or_dir(serverRoot, PR_FILE_DIRECTORY, "alias", 0, PR_FILE_DIRECTORY)) {
errorRpt(INCORRECT_USAGE, getResourceString(DBT_INVALID_SERVER_ROOT));
}
+ /* if we got here, serverRoot has passed our rigorous integrity checks and contains an alias directory */
+ path = PR_smprintf("%s%calias", serverRoot, FILE_PATHSEP);
alist = list_directory(path);
if (alist == NULL) {
errorRpt(INCORRECT_USAGE, getResourceString(DBT_READ_ALIAS));
@@ -1900,6 +2093,12 @@
#endif
oldRoot = getParameter("old_server_root", getResourceString(DBT_OLD_SERVER_ROOT));
+ if (!verify_file_or_dir(oldRoot, PR_FILE_DIRECTORY, "alias", 0, PR_FILE_DIRECTORY) ||
+ !is_valid_path_string(alias))
+ {
+ PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), oldRoot);
+ errorRpt(INCORRECT_USAGE, msg);
+ }
newRoot = getenv("NETSITE_ROOT");
aliasLen = PORT_Strlen(alias);
@@ -1932,13 +2131,41 @@
sprintf(scratch, mask, newRoot, FILE_PATHSEP, FILE_PATHSEP, alias, cert7);
if (PR_SUCCESS == PR_Access(scratch, PR_ACCESS_EXISTS)) {
- PR_Rename(scratch, backCertFile);
+ /* really make sure the file exists */
+ char *dir = PR_smprintf("%s%calias", newRoot, FILE_PATHSEP);
+ char *file = PR_smprintf("%s-%s.db", alias, cert7);
+ if (verify_file_or_dir(dir, PR_FILE_DIRECTORY, file, 0, PR_FILE_FILE)) {
+ PR_Rename(scratch, backCertFile);
+ if (!verify_file_or_dir(backCertFile, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
+ PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), backCertFile);
+ errorRpt(INCORRECT_USAGE, msg);
+ }
+ } else {
+ PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), scratch);
+ errorRpt(INCORRECT_USAGE, msg);
+ }
+ PR_smprintf_free(dir);
+ PR_smprintf_free(file);
}
sprintf(scratch, mask, newRoot, FILE_PATHSEP, FILE_PATHSEP, alias, key3);
if (PR_SUCCESS == PR_Access(scratch, PR_ACCESS_EXISTS)) {
- PR_Rename(scratch, backKeyFile);
+ /* really make sure the file exists */
+ char *dir = PR_smprintf("%s%calias", newRoot, FILE_PATHSEP);
+ char *file = PR_smprintf("%s-%s.db", alias, key3);
+ if (verify_file_or_dir(dir, PR_FILE_DIRECTORY, file, 0, PR_FILE_FILE)) {
+ PR_Rename(scratch, backKeyFile);
+ if (!verify_file_or_dir(backKeyFile, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
+ PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), backKeyFile);
+ errorRpt(INCORRECT_USAGE, msg);
+ }
+ } else {
+ PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), scratch);
+ errorRpt(INCORRECT_USAGE, msg);
+ }
+ PR_smprintf_free(dir);
+ PR_smprintf_free(file);
}
PORT_Free(backCertFile);
@@ -1963,11 +2190,12 @@
fileName = (char *) PORT_Alloc(i);
sprintf(fileName, mask, oldRoot, FILE_PATHSEP, FILE_PATHSEP, alias, cert);
-
- if (PR_SUCCESS == PR_Access(fileName, PR_ACCESS_EXISTS)) {
+ if ((PR_SUCCESS == PR_Access(fileName, PR_ACCESS_EXISTS)) &&
+ verify_file_or_dir(fileName, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
oldCert = PORT_Strdup(fileName);
sprintf(fileName, mask, oldRoot, FILE_PATHSEP, FILE_PATHSEP, alias, key);
- if (PR_SUCCESS == PR_Access(fileName, PR_ACCESS_EXISTS)) {
+ if ((PR_SUCCESS == PR_Access(fileName, PR_ACCESS_EXISTS)) &&
+ verify_file_or_dir(fileName, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
} else {
PORT_Free(oldCert);
oldCert = 0;
@@ -1982,32 +2210,37 @@
PORT_Free(oldCert);
} else {
sprintf(fileName, mask, oldRoot, FILE_PATHSEP, FILE_PATHSEP, alias, cert);
- if (PR_SUCCESS == PR_Access(fileName, PR_ACCESS_EXISTS)) {
+ if ((PR_SUCCESS == PR_Access(fileName, PR_ACCESS_EXISTS)) &&
+ verify_file_or_dir(fileName, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
} else {
PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), fileName);
errorRpt(INCORRECT_USAGE, msg);
}
oldCert = PORT_Strdup(fileName);
sprintf(fileName, mask, oldRoot, FILE_PATHSEP, FILE_PATHSEP, alias, key);
- if (PR_SUCCESS == PR_Access(fileName, PR_ACCESS_EXISTS)) {
- char * scratch;
- i += sizeof(cmd) + PORT_Strlen(newRoot) + aliasLen + 20; /* overkill but safe */
- scratch = (char *) PORT_Alloc(i);
- sprintf(scratch, cmd, oldCert, newRoot, FILE_PATHSEP, FILE_PATHSEP, alias, cert7);
- if (system(normalizeCommandLine(scratch))) {
- errorRpt(INCORRECT_USAGE, getResourceString(DBT_UNABLE_TO_MIGRATE));
- }
- sprintf(scratch, cmd, fileName, newRoot, FILE_PATHSEP, FILE_PATHSEP, alias, key3);
- if (system(normalizeCommandLine(scratch))) {
- errorRpt(INCORRECT_USAGE, getResourceString(DBT_UNABLE_TO_MIGRATE));
- }
- PORT_Free(scratch);
- PORT_Free(oldCert);
+ if ((PR_SUCCESS == PR_Access(fileName, PR_ACCESS_EXISTS)) &&
+ verify_file_or_dir(fileName, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
+ char *newfile = PR_smprintf("%s%calias%c%s-%s.db",
+ newRoot, FILE_PATHSEP, FILE_PATHSEP,
+ alias, cert7);
+ if (!copyFile(oldCert, newfile) ||
+ !verify_file_or_dir(newfile, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
+ errorRpt(INCORRECT_USAGE, getResourceString(DBT_UNABLE_TO_MIGRATE));
+ }
+ PR_smprintf_free(newfile);
+ newfile = PR_smprintf("%s%calias%c%s-%s.db",
+ newRoot, FILE_PATHSEP, FILE_PATHSEP,
+ alias, key3);
+ if (!copyFile(fileName, newfile) ||
+ !verify_file_or_dir(newfile, PR_FILE_FILE, NULL, 0, (PRFileType)0)) {
+ errorRpt(INCORRECT_USAGE, getResourceString(DBT_UNABLE_TO_MIGRATE));
+ }
+ PR_smprintf_free(newfile);
} else {
- PORT_Free(oldCert);
PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), fileName);
errorRpt(INCORRECT_USAGE, msg);
}
+ PORT_Free(oldCert);
}
PORT_Free(fileName);
}
@@ -2034,6 +2267,7 @@
char * m = getenv("REQUEST_METHOD");
char * qs = 0;
char *sie;
+ char msg[BIG_LINE];
#if 0
CGI_Debug("security");
@@ -2056,7 +2290,7 @@
fflush(stdout);
/* This cgi only handle post request*/
- if(!PORT_Strcmp(m, "GET")) {
+ if(!m || PORT_Strcmp(m, "POST")) {
return 0;
}
@@ -2067,7 +2301,12 @@
{
char* operation = getParameter("formop",getResourceString(DBT_OP));
- if (!PORT_Strcmp(operation, "MIGRATE_DB")) {
+ if (!operation) {
+ /* if we got here it means front end pass back
+ a bogus operation string */
+ PR_snprintf(line, sizeof(line), getResourceString(DBT_NO_OP), operation);
+ errorRpt(INCORRECT_USAGE, line);
+ } else if (!PORT_Strcmp(operation, "MIGRATE_DB")) {
keyCertMigrate(getParameter("alias",getResourceString(DBT_ALIAS)),
sie);
@@ -2075,6 +2314,20 @@
/*only initialize db when we are not trying to migrate
if we initialize db then we won't be able to migrate because
security library will hog up the file and we can not remove it.*/
+ char *dbdir = PR_smprintf("%s%calias", getenv("NETSITE_ROOT"), FILE_PATHSEP);
+ char *certdbname = PR_smprintf("%s-cert8.db", sie);
+ char *keydbname = PR_smprintf("%s-key3.db", sie);
+ if (!is_valid_path_string(sie) ||
+ !verify_file_or_dir(dbdir, PR_FILE_DIRECTORY, certdbname, 0, PR_FILE_FILE) ||
+ !verify_file_or_dir(dbdir, PR_FILE_DIRECTORY, keydbname, 0, PR_FILE_FILE)) {
+ PR_snprintf(msg, sizeof(msg), getResourceString(DBT_NO_FILE_EXISTS), certdbname);
+ errorRpt(INCORRECT_USAGE, msg);
+ }
+ PR_smprintf_free(dbdir);
+ PR_smprintf_free(certdbname);
+ PR_smprintf_free(keydbname);
+
+ /* we got here, we think sie is a valid prefix */
securityInitialization(sie);
if (!PORT_Strcmp(operation, "LIST_CERTIFICATE")) {
@@ -2083,9 +2336,17 @@
/* fprintf(stdout, "total_cert:%d",num_of_certs++); */
} else if (!PORT_Strcmp(operation, "CHANGE_TRUST")) {
+ char *endptr = NULL;
+ char *truststr = getParameter("trust_flag",getResourceString(DBT_TRUST));
+ int trustflag = strtol(truststr, &endptr, 0);
+ if ((*truststr == '\0') || !endptr || (*endptr != '\0')) {
+ /* invalid trust flags */
+ errorRpt(GENERAL_FAILURE, getResourceString(DBT_TRUST_SET_FAIL));
+ }
+
/* change trust */
setTrust(getParameter("certfingerprint",getResourceString(DBT_CERT_FINGERPRINT)),
- atoi(getParameter("trust_flag",getResourceString(DBT_TRUST))));
+ trustflag);
} else if (!PORT_Strcmp(operation, "FIND_CERTIFICATE")) {
/* view cert */
@@ -2169,12 +2430,12 @@
} else if (!PORT_Strcmp(operation, "FIND_CRL_CKL")) {
/* print detail information of a crl/ckl */
char *type = get_cgi_var("list_type", NULL, NULL);
- fprintf(stdout, "<%s>\n", type);
+ fprintf(stdout, "<%s>\n", type?type:"");
showCRLRow(cmgFindCrlByName(certdb,
getParameter("crlname", getResourceString(DBT_MISSING_FILE)),
- !PORT_Strcmp(type, "CKL")? SEC_KRL_TYPE : SEC_CRL_TYPE),
+ (type && !PORT_Strcmp(type, "CKL"))? SEC_KRL_TYPE : SEC_CRL_TYPE),
PR_TRUE,
- ((!PORT_Strcmp("CRL", type))?SEC_CRL_TYPE:SEC_KRL_TYPE));
+ ((type && !PORT_Strcmp("CRL", type))?SEC_CRL_TYPE:SEC_KRL_TYPE));
fprintf(stdout, "</%s>\n", type);
} else if (!PORT_Strcmp(operation, "LIST_ALIAS")) {
Index: snmpconf.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/snmpconf.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- snmpconf.c 31 Mar 2006 22:58:20 -0000 1.5
+++ snmpconf.c 11 May 2006 14:29:30 -0000 1.6
@@ -188,7 +188,7 @@
op=get_cgi_var("op", NULL, NULL);
- logMsg("op=%s\n", op);
+ logMsg("op=%s\n", op?op:"");
if (op == NULL) {
rpt_err(INCORRECT_USAGE, i18nMsg(DBT_NO_OPERATION, "No operation defined"), NULL, NULL);
@@ -306,6 +306,11 @@
operation = tab+1;
logMsg("%s=%s\n", name, operation);
+ if (strlen(operation) > (sizeof(op_buf)-strlen("ALLOW OPERATIONS"))) {
+ logMsg("Error: community operation [%s] is too large\n", community);
+ PR_snprintf(error_info, sizeof(error_info), i18nMsg(DBT_UNKNOWN_OPERATION, "Unknown Operation (%s)"), op);
+ rpt_err(INCORRECT_USAGE, error_info, NULL, NULL);
+ }
PR_snprintf(op_buf, sizeof(op_buf), "ALLOW %s OPERATIONS", operation);
list = add_community_entry(list, name, op_buf);
Index: snmpmctl.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/snmpmctl.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- snmpmctl.c 31 Mar 2006 22:58:20 -0000 1.5
+++ snmpmctl.c 11 May 2006 14:29:30 -0000 1.6
@@ -197,7 +197,12 @@
}
action_type = get_cgi_var("ACTION", NULL, NULL);
- if (!strcmp(action_type, "START")) {
+ if (!action_type) {
+ PR_snprintf(error_info, sizeof(error_info), i18nMsg(DBT_UNKNOWN_CMD,"Command (%s) not understood"), "");
+ logMsg("%s\n", error_info);
+ rpt_err(INCORRECT_USAGE, error_info, NULL, NULL);
+ }
+ else if (!strcmp(action_type, "START")) {
logMsg("START\n");
check_superuser();
magent_shutdown(0);
Index: statpingserv.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/statpingserv.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- statpingserv.c 31 Mar 2006 22:58:20 -0000 1.4
+++ statpingserv.c 11 May 2006 14:29:30 -0000 1.5
@@ -62,6 +62,8 @@
PRHostEnt hent;
char buf[PR_NETDB_BUF_SIZE];
PRStatus err;
+ char gifbuf[BUFSIZ];
+ PRInt32 bytes;
PRFileDesc *req_socket= NULL;
int retcode;
@@ -71,10 +73,12 @@
char *host;
int port;
- FILE *gif;
+ PRFileDesc *gif;
int character;
int count=0;
char *file;
+ char *portstr;
+ struct PRFileInfo64 prfileinfo;
m = getenv("REQUEST_METHOD");
/*
@@ -91,13 +95,21 @@
result = get_cgi_var("result", NULL, NULL);
host = get_cgi_var("host", NULL, NULL);
- port = atoi(get_cgi_var("port", NULL, NULL));
+ portstr = get_cgi_var("port", NULL, NULL);
+ if (portstr) {
+ port = atoi(portstr);
+ } else {
+ port = 0;
+ }
if(result && !strcmp(result, "text"))
fprintf(stdout, "Content-type: text/html\n");
else
fprintf(stdout, "Content-type: image/gif\n");
+ if (!host || !port) {
+ rpt_err(APP_ERROR, "Invalid hostname and/or port number!", NULL, NULL);
+ }
if(!isdigit(host[0])) {
err = PR_GetHostByName(host, buf, sizeof(buf), &hent);
if(err == PR_FAILURE)
@@ -130,21 +142,34 @@
PR_Close(req_socket);
- gif = fopen(file, "rb");
- if(!gif)
+ if ((PR_FAILURE == PR_GetFileInfo64(file, &prfileinfo)) ||
+ (prfileinfo.type != PR_FILE_FILE)) {
rpt_err(APP_ERROR, "Cannot open gif file!", NULL, NULL);
- while((character = fgetc(gif)) != EOF)
- count++;
- fclose(gif);
+ }
- fprintf(stdout, "Content-length: %d\n\n", count);
+ fprintf(stdout, "Content-length: %ld\n\n", (size_t)prfileinfo.size);
+ fflush(stdout);
- gif = fopen(file, "rb");
+ PR_Sync(PR_STDOUT);
+ gif = PR_Open(file, PR_RDONLY, 0);
if(!gif)
rpt_err(APP_ERROR, "Cannot open gif file!", NULL, NULL);
- while((character = fgetc(gif)) != EOF)
- fputc(character, stdout);
- fclose(gif);
+ while (0 < (bytes = PR_Read(gif, gifbuf, sizeof(gifbuf)))) {
+ PRInt32 remaining = bytes;
+ PRInt32 byteswritten = 0;
+ while (((byteswritten = PR_Write(PR_STDOUT, gifbuf+byteswritten, remaining)) != remaining) &&
+ (byteswritten > 0)) {
+ remaining -= byteswritten;
+ }
+ if (byteswritten < 0) {
+ rpt_err(APP_ERROR, "Cannot write gif to stdout!", NULL, NULL);
+ }
+ }
+ if (bytes < 0) {
+ rpt_err(APP_ERROR, "Cannot read gif to write to stdout!", NULL, NULL);
+ }
+ PR_Sync(PR_STDOUT);
+ PR_Close(gif);
}
return 0;
Index: viewdata.c
===================================================================
RCS file: /cvs/dirsec/adminserver/admserv/cgi-src40/viewdata.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- viewdata.c 31 Mar 2006 22:58:20 -0000 1.5
+++ viewdata.c 11 May 2006 14:29:30 -0000 1.6
@@ -233,9 +233,15 @@
/* Get the domain */
tmp = strdup(sie);
- tmp2 = strrchr(tmp, ',');
+ if (!(tmp2 = strrchr(tmp, ','))) {
+ free(tmp);
+ return 1;
+ }
tmp2[0] = '\0';
- domain = strrchr(tmp, ',');
+ if (!(domain = strrchr(tmp, ','))) {
+ free(tmp);
+ return 1;
+ }
domain++;
tmp2[0] = ',';
@@ -457,81 +463,6 @@
ldap_value_free(vals);
}
}
- else if(directive_is(line, "CHECK_UPGRADE")) {
- char *tmp = strdup(sie);
- char *isie;
- char **vals;
- char *sie_product_version;
- char *html_line;
-#if 0
-
- /* First, get the current SIE's product version. */
- isie = strtok(tmp, ",");
- isie = strtok(NULL, "\0");
- isie++;
- while(*isie == ' ')
- isie++;
-
- if((ldapError = ldap_search_s(server, isie, LDAP_SCOPE_BASE,
- "(objectclass=*)", NULL, 0, &entry)) != LDAP_SUCCESS)
- return 1;
- if(vals = ldap_get_values(server, entry, "nsproductversion")) {
- sie_product_version = strdup(vals[0]);
- ldap_value_free(vals);
- }
-
- /*
- * Next, get the currently-shipping product version of the product we're interested in.
- * Check the secret Netcenter URL. No need to init SSL in this case since the site is always insecure.
- */
-
- if(!get_bindinfo(&binddn, &bindpw))
- exit(0);
-
- nbuf = (bufstruct *) new_buffer(NBUF_SIZE);
-
- request = PR_smprintf(getResourceString(DBT_NETCENTER_GET_REQ), binddn);
- sockd = make_http_request("http",
- getResourceString(DBT_NETCENTER_HOST),
- atoi(getResourceString(DBT_NETCENTER_PORT)),
- request, 60, &errorcode);
- PR_smprintf_free(request);
-
- if (sockd == NULL) {
- continue;
- }
-
- /* Why is the third parameter not used in parse_http_header ?? */
- if (parse_http_header(sockd, nbuf, "Enterprise") < 0) {
- end_http_request(sockd);
- continue;
- }
-
- while( (html_line = get_line_from_fd(sockd, nbuf)) != (char *) NULL) {
- if((strstr(sie, "Messaging") && strstr(html_line, "Messaging")) ||
- (strstr(sie, "Administration") && strstr(html_line, "Administration")) ||
- (strstr(sie, "Directory") && strstr(html_line, "Directory")) ||
- (strstr(sie, "Enterprise") && strstr(html_line, "Enterprise")) ||
- (strstr(sie, "Certificate") && strstr(html_line, "Certificate")) ||
- (strstr(sie, "Application") && strstr(html_line, "Application")) ||
- (strstr(sie, "Biller") && strstr(html_line, "Biller"))) {
- /*
- * Get the product version. If the version is higher than the server we're looking at,
- * display an upgrade link.
- */
- if(tmp) free(tmp);
- tmp = strtok(html_line, "=");
- tmp = strtok(NULL, "\n");
- if(setupVersionCompare(tmp, sie_product_version) > 0)
- fprintf(stdout, (const char*)getResourceString(DBT_MAIN_PRODUCT_VERSION), getResourceString(DBT_NETCENTER_SERVER_PRODUCT_URL));
- else
- fprintf(stdout, getResourceString(DBT_MAIN_UPGRADE_AVAILABLE));
-
- break;
- }
- }
-#endif
- }
else if(directive_is(line, "SHOW_URL")) {
char *text;
char *url;
--- userinfo.c DELETED ---