Beispiel #1
0
/* Search a separator forward. */
static inline uint
search_separator(const char **ip, const char *ipe, const char *item, int direction)
{   uint slen = 0;
    for (slen = 0; (*ip - ipe) * direction < 0; (*ip) += direction)
	if((slen = gs_file_name_check_separator(*ip, ipe - *ip, item)) != 0)
	    break;
    return slen;
}
Beispiel #2
0
/* strings of the permitgroup array. */
static int
check_file_permissions_reduced(i_ctx_t *i_ctx_p, const char *fname, int len,
			const char *permitgroup)
{
    long i;
    ref *permitlist = NULL;
    /* an empty string (first character == 0) if '\' character is */
    /* recognized as a file name separator as on DOS & Windows	  */
    const char *win_sep2 = "\\";
    bool use_windows_pathsep = (gs_file_name_check_separator(win_sep2, 1, win_sep2) == 1);
    uint plen = gp_file_name_parents(fname, len);

    /* Assuming a reduced file name. */

    if (dict_find_string(&(i_ctx_p->userparams), permitgroup, &permitlist) <= 0)
        return 0;	/* if Permissions not found, just allow access */

    for (i=0; i<r_size(permitlist); i++) {
        ref permitstring;
	const string_match_params win_filename_params = {
		'*', '?', '\\', true, true	/* ignore case & '/' == '\\' */
	};
	const byte *permstr;
	uint permlen;
	int cwd_len = 0;

	if (array_get(imemory, permitlist, i, &permitstring) < 0 ||
	    r_type(&permitstring) != t_string 
	   )    
	    break;	/* any problem, just fail */
	permstr = permitstring.value.bytes;
	permlen = r_size(&permitstring);
	/* 
	 * Check if any file name is permitted with "*".
	 */
	if (permlen == 1 && permstr[0] == '*')
	    return 0;		/* success */
	/* 
	 * If the filename starts with parent references, 
	 * the permission element must start with same number of parent references.
	 */
	if (plen != 0 && plen != gp_file_name_parents((const char *)permstr, permlen))
	    continue;
	cwd_len = gp_file_name_cwds((const char *)permstr, permlen);
	/*
	 * If the permission starts with "./", absolute paths
	 * are not permitted.
	 */
	if (cwd_len > 0 && gp_file_name_is_absolute(fname, len))
	    continue;
	/*
	 * If the permission starts with "./", relative paths
	 * with no "./" are allowed as well as with "./".
	 * 'fname' has no "./" because it is reduced.
	 */
        if (string_match( (const unsigned char*) fname, len,
			  permstr + cwd_len, permlen - cwd_len, 
		use_windows_pathsep ? &win_filename_params : NULL))
	    return 0;		/* success */
    }
    /* not found */
    return e_invalidfileaccess;
}
Beispiel #3
0
/*
 * Combine a file name with a prefix.
 * Concatenates two paths and reduce parent references and current 
 * directory references from the concatenation when possible.
 * The trailing zero byte is being added.
 *
 * Returns "gp_combine_success" if OK and sets '*blen' to the length of
 * the combined string. If the combined string is too small for the buffer
 * length passed in (as defined by the initial value of *blen), then the
 * "gp_combine_small_buffer" code is returned.
 *
 * Also tolerates/skips leading IODevice specifiers such as %os% or %rom%
 * When there is a leading '%' in the 'fname' no other processing is done.
 *
 * Examples : 
 *	"/gs/lib" + "../Resource/CMap/H" --> "/gs/Resource/CMap/H"
 *	"C:/gs/lib" + "../Resource/CMap/H" --> "C:/gs/Resource/CMap/H"
 *	"hard disk:gs:lib" + "::Resource:CMap:H" --> 
 *		"hard disk:gs:Resource:CMap:H"
 *	"DUA1:[GHOSTSCRIPT.LIB" + "-.RESOURCE.CMAP]H" --> 
 *		"DUA1:[GHOSTSCRIPT.RESOURCE.CMAP]H"
 *      "\\server\share/a/b///c/../d.e/./" + "../x.e/././/../../y.z/v.v" --> 
 *		"\\server\share/a/y.z/v.v"
 *	"%rom%lib/" + "gs_init.ps" --> "%rom%lib/gs_init.ps
 *	"" + "%rom%lib/gs_init.ps" --> "%rom%lib/gs_init.ps"
 */
gp_file_name_combine_result
gp_file_name_combine_generic(const char *prefix, uint plen, const char *fname, uint flen, 
		    bool no_sibling, char *buffer, uint *blen)
{
    /*
     * THIS CODE IS SHARED FOR MULTIPLE PLATFORMS.
     * PLEASE DON'T CHANGE IT FOR A SPECIFIC PLATFORM.
     * Change gp_file_name_combine instead.
     */
    char *bp = buffer, *bpe = buffer + *blen;
    const char *ip, *ipe;
    uint slen;
    uint infix_type = 0; /* 0=none, 1=current, 2=parent. */
    uint infix_len = 0;
    uint rlen = gp_file_name_root(fname, flen);
    /* We need a special handling of infixes only immediately after a drive. */

    if ( flen > 0 && fname[0] == '%') {
    	/* IoDevice -- just return the fname as-is since this */
	/* function only handles the default file system */
	/* NOTE: %os% will subvert the normal processing of prefix and fname */
	ip = fname;
	*blen = flen;
	if (!append(&bp, bpe, &ip, flen))
	    return gp_combine_small_buffer;
	return gp_combine_success;
    }
    if (rlen != 0) {
        /* 'fname' is absolute, ignore the prefix. */
	ip = fname;
	ipe = fname + flen;
    } else {
        /* Concatenate with prefix. */
	ip = prefix;
	ipe = prefix + plen;
	rlen = gp_file_name_root(prefix, plen);
    }
    if (!append(&bp, bpe, &ip, rlen))
	return gp_combine_small_buffer;
    slen = gs_file_name_check_separator(bp, buffer - bp, bp); /* Backward search. */
    if (rlen != 0 && slen == 0) {
	/* Patch it against names like "c:dir" on Windows. */
	const char *sep = gp_file_name_directory_separator();

	slen = strlen(sep);
	if (!append(&bp, bpe, &sep, slen))
	    return gp_combine_small_buffer;
	rlen += slen;
    }
    for (;;) {
	const char *item = ip;
	uint ilen;

	slen = search_separator(&ip, ipe, item, 1);
	ilen = ip - item;
	if (ilen == 0 && !gp_file_name_is_empty_item_meanful()) {
	    ip += slen;
	    slen = 0;
	} else if (gp_file_name_is_current(item, ilen)) {
	    /* Skip the reference to 'current', except the starting one.
	     * We keep the starting 'current' for platforms, which
	     * require relative paths to start with it.
	     */
	    if (bp == buffer) {
		if (!append(&bp, bpe, &item, ilen))
		    return gp_combine_small_buffer;
		infix_type = 1;
		infix_len = ilen;
	    } else {
		ip += slen;
		slen = 0;
	    }
	} else if (!gp_file_name_is_parent(item, ilen)) {
	    if (!append(&bp, bpe, &item, ilen))
		return gp_combine_small_buffer;
	    /* The 'item' pointer is now broken; it may be restored using 'ilen'. */
	} else if (bp == buffer + rlen + infix_len) {
	    /* Input is a parent and the output only contains a root and an infix. */
	    if (rlen != 0)
		return gp_combine_cant_handle;
	    switch (infix_type) {
		case 1:
		    /* Replace the infix with parent. */
		    bp = buffer + rlen; /* Drop the old infix, if any. */
		    infix_len = 0;
		    /* Falls through. */
		case 0:
		    /* We have no infix, start with parent. */
		    if ((no_sibling && ipe == fname + flen && flen != 0) || 
			    !gp_file_name_is_partent_allowed())
			return gp_combine_cant_handle;
		    /* Falls through. */
		case 2:
		    /* Append one more parent - falls through. */
		    DO_NOTHING;
	    }
	    if (!append(&bp, bpe, &item, ilen))
		return gp_combine_small_buffer;
	    infix_type = 2;
	    infix_len += ilen;
	    /* Recompute the separator length. We cannot use the old slen on Mac OS. */
	    slen = gs_file_name_check_separator(ip, ipe - ip, ip);
	} else {
	    /* Input is a parent and the output continues after infix. */
	    /* Unappend the last separator and the last item. */
	    uint slen1 = gs_file_name_check_separator(bp, buffer + rlen - bp, bp); /* Backward search. */
	    char *bie = bp - slen1;

	    bp = bie;
	    DISCARD(search_separator((const char **)&bp, buffer + rlen, bp, -1));
	    /* The cast above quiets a gcc warning. We believe it's a bug in the compiler. */
	    /* Skip the input with separator. We cannot use slen on Mac OS. */
	    ip += gs_file_name_check_separator(ip, ipe - ip, ip);
	    if (no_sibling) {
		const char *p = ip;

		DISCARD(search_separator(&p, ipe, ip, 1));
		if (p - ip != bie - bp || memcmp(ip, bp, p - ip))    
		    return gp_combine_cant_handle;
	    }
	    slen = 0;
	}
	if (slen) {
	    if (bp == buffer + rlen + infix_len)
		infix_len += slen;
	    if (!append(&bp, bpe, &ip, slen))
		return gp_combine_small_buffer;
	}
	if (ip == ipe) {
	    if (ipe == fname + flen) {
		/* All done.
		 * Note that the case (prefix + plen == fname && flen == 0)
		 * falls here without appending a separator.
		 */
		const char *zero="";

		if (bp == buffer) {
		    /* Must not return empty path. */
		    const char *current = gp_file_name_current();
		    int clen = strlen(current);

		    if (!append(&bp, bpe, &current, clen))
			return gp_combine_small_buffer;
		}
		*blen = bp - buffer;
		if (!append(&bp, bpe, &zero, 1))
		    return gp_combine_small_buffer;
		return gp_combine_success;
	    } else {
	        /* ipe == prefix + plen */
		/* Switch to fname. */
		ip = fname;
		ipe = fname + flen;
		if (slen == 0) {
		    /* Insert a separator. */
		    const char *sep;
    
		    slen = search_separator(&ip, ipe, fname, 1);
		    sep = (slen != 0 ? gp_file_name_directory_separator() 
		                    : gp_file_name_separator());
		    slen = strlen(sep);
		    if (bp == buffer + rlen + infix_len)
			infix_len += slen;
		    if (!append(&bp, bpe, &sep, slen))
			return gp_combine_small_buffer;
		    ip = fname; /* Switch to fname. */
		}
	    }
	}
    }
}
/* Write the actual file name at fname. */
FILE *
gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
{
    UINT n;
    DWORD l;
    HANDLE hfile = INVALID_HANDLE_VALUE;
    int fd = -1;
    FILE *f = NULL;
    char sTempDir[_MAX_PATH];
    char sTempFileName[_MAX_PATH];

    memset(fname, 0, gp_file_name_sizeof);
    if (!gp_file_name_is_absolute(prefix, strlen(prefix))) {
	int plen = sizeof(sTempDir);

	if (gp_gettmpdir(sTempDir, &plen) != 0)
	    l = GetTempPath(sizeof(sTempDir), sTempDir);
	else
	    l = strlen(sTempDir);
    } else {
	strncpy(sTempDir, prefix, sizeof(sTempDir));
	prefix = "";
	l = strlen(sTempDir);
    }
    /* Fix the trailing terminator so GetTempFileName doesn't get confused */
    if (sTempDir[l-1] == '/')
	sTempDir[l-1] = '\\';		/* What Windoze prefers */

    if (l <= sizeof(sTempDir)) {
	n = GetTempFileName(sTempDir, prefix, 0, sTempFileName);
	if (n == 0) {
	    /* If 'prefix' is not a directory, it is a path prefix. */
	    int l = strlen(sTempDir), i;

	    for (i = l - 1; i > 0; i--) {
		uint slen = gs_file_name_check_separator(sTempDir + i, l, sTempDir + l);

		if (slen > 0) {
		    sTempDir[i] = 0;   
		    i += slen;
		    break;
		}
	    }
	    if (i > 0)
		n = GetTempFileName(sTempDir, sTempDir + i, 0, sTempFileName);
	}
	if (n != 0) {
	    hfile = CreateFile(sTempFileName, 
		GENERIC_READ | GENERIC_WRITE | DELETE,
		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL /* | FILE_FLAG_DELETE_ON_CLOSE */, 
		NULL);
	    /*
	     * Can't apply FILE_FLAG_DELETE_ON_CLOSE due to 
	     * the logics of clist_fclose. Also note that
	     * gdev_prn_render_pages requires multiple temporary files
	     * to exist simultaneousely, so that keeping all them opened
	     * may exceed available CRTL file handles.
	     */
	}
    }
    if (hfile != INVALID_HANDLE_VALUE) {
	/* Associate a C file handle with an OS file handle. */
	fd = _open_osfhandle((long)hfile, 0);
	if (fd == -1)
	    CloseHandle(hfile);
	else {
	    /* Associate a C file stream with C file handle. */
	    f = fdopen(fd, mode);
	    if (f == NULL)
		_close(fd);
	}
    }
    if (f != NULL) {
	if ((strlen(sTempFileName) < gp_file_name_sizeof))
	    strncpy(fname, sTempFileName, gp_file_name_sizeof - 1);
	else {
	    /* The file name is too long. */
	    fclose(f);
	    f = NULL;
	}
    }
    if (f == NULL)
	eprintf1("**** Could not open temporary file '%s'\n", fname);
    return f;
}