krb5: Fix out-of-tree SQLite3 ccache perms issue
SQLite3 defaults to 0644 unless overridden, relying on the process' umask to make that tighter. Our in-tree SQLite3 uses 0600 as the permissions for DB files it creates. Out-of-tree builds of SQLite3 probably get the 0644 default. We can't change the umask in libraries -- it's not thread-safe. So this commit changes the SCC ccache type's default ccname to include an intermediate directory which is created with `mkdir(2)` with permissions set to 0700, then it chmods the DB file to 0644.
This commit is contained in:
		| @@ -61,8 +61,18 @@ typedef struct krb5_scache { | ||||
|  | ||||
| #define	SCACHE(X)	((krb5_scache *)(X)->data.data) | ||||
|  | ||||
| /* | ||||
|  * Because we can't control what permissions SQLite3 (if not in-tree) will use, | ||||
|  * and we're a library and can't set the umask.  We can't even determine the | ||||
|  * current umask in a thread-safe way (not easily), and we can't tell if some | ||||
|  * other thread might change it.  So what we'll do is put the SQLite3-based | ||||
|  * ccache file in its own directory so we can create that directory with | ||||
|  * mkdir(2) and the correct permissions. | ||||
|  */ | ||||
|  | ||||
| #define SCACHE_DEF_NAME		"Default-cache" | ||||
| #define KRB5_SCACHE_DB		"%{TEMP}/krb5scc_%{uid}" | ||||
| #define KRB5_SCACHE_DIR		"%{TEMP}/krb5scc_%{uid}" | ||||
| #define KRB5_SCACHE_DB		KRB5_SCACHE_DIR "scc" | ||||
| #define KRB5_SCACHE_NAME	"SCC:"   KRB5_SCACHE_DB ":" SCACHE_DEF_NAME | ||||
|  | ||||
| #define SCACHE_INVALID_CID	((sqlite_uint64)-1) | ||||
| @@ -226,6 +236,43 @@ exec_stmt(krb5_context context, sqlite3 *db, const char *str, | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /* See block comment at the top of this file */ | ||||
| static krb5_error_code | ||||
| make_dir(krb5_context context, const char *name) | ||||
| { | ||||
|     krb5_error_code ret = 0; | ||||
|     char *s, *p; | ||||
|  | ||||
|     /* We really need a dirname() in roken; lib/krb5/fcache.c has one */ | ||||
|     if ((s = strdup(name)) == NULL) | ||||
|         return krb5_enomem(context); | ||||
|     for (p = s + strlen(s); p > s; p--) { | ||||
| #ifdef WIN32 | ||||
|         if (*p != '/' && *p != '\\') | ||||
|             continue; | ||||
| #else | ||||
|         if (*p != '/') | ||||
|             continue; | ||||
| #endif | ||||
|         *p = '\0'; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     /* If p == s then DB in current directory -- nothing we can do */ | ||||
|     if (p > s && mkdir(s, 0700) == -1) | ||||
|         ret = errno; | ||||
|     free(s); | ||||
|  | ||||
|     /* If we created it, we're good, else there's nothing we can do */ | ||||
|     if (ret == EEXIST) | ||||
|         return 0; | ||||
|     if (ret) | ||||
|         krb5_set_error_message(context, ret, | ||||
|                                N_("Error making directory for scache file %s", ""), | ||||
|                                name); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static krb5_error_code | ||||
| default_db(krb5_context context, const char *name, sqlite3 **db, char **file) | ||||
| { | ||||
| @@ -258,10 +305,18 @@ default_db(krb5_context context, const char *name, sqlite3 **db, char **file) | ||||
|     } | ||||
|     free(s); | ||||
|  | ||||
|     /* Strip off any residue from default name */ | ||||
| #ifdef WIN32 | ||||
|     if (f[0] && f[1] == ':' && (s = strrchr(f, ':')) != &f[1]) | ||||
|         *s = '\0'; | ||||
| #else | ||||
|     if ((s = strrchr(f, ':'))) | ||||
|         *s = '\0'; | ||||
| #endif | ||||
|  | ||||
|     ret = sqlite3_open_v2(f, db, SQLITE_OPEN_READWRITE, NULL); | ||||
|     ret = make_dir(context, f); | ||||
|     if (ret == 0) | ||||
|         ret = sqlite3_open_v2(f, db, SQLITE_OPEN_READWRITE, NULL); | ||||
|     if (ret != SQLITE_OK) { | ||||
|         sqlite3_close(*db); | ||||
| 	krb5_clear_error_message(context); | ||||
| @@ -269,6 +324,14 @@ default_db(krb5_context context, const char *name, sqlite3 **db, char **file) | ||||
| 	return ENOENT; | ||||
|     } | ||||
|  | ||||
| #ifndef WIN32 | ||||
|     /* | ||||
|      * Just in case we're using an out-of-tree SQLite3.  See block comment at | ||||
|      * the top of this file, near KRB5_SCACHE_DIR's definition. | ||||
|      */ | ||||
|     (void) chmod(f, 0600); | ||||
| #endif | ||||
|  | ||||
|     if (file) | ||||
|         *file = f; | ||||
|     else | ||||
| @@ -424,6 +487,9 @@ open_database(krb5_context context, krb5_scache *s, int flags) | ||||
|     if (!(flags & SQLITE_OPEN_CREATE) && stat(s->file, &st) == 0 && | ||||
|         st.st_size == 0) | ||||
|         return ENOENT; | ||||
|  | ||||
|     ret = make_dir(context, s->file); | ||||
|     if (ret == 0) | ||||
|     ret = sqlite3_open_v2(s->file, &s->db, SQLITE_OPEN_READWRITE|flags, NULL); | ||||
|     if (ret) { | ||||
| 	if (s->db) { | ||||
| @@ -519,6 +585,14 @@ make_database(krb5_context context, krb5_scache *s) | ||||
|     ret = prepare_stmt(context, s->db, &s->umaster, SQL_UMASTER); | ||||
|     if (ret) goto out; | ||||
|  | ||||
| #ifndef WIN32 | ||||
|     /* | ||||
|      * Just in case we're using an out-of-tree SQLite3.  See block comment at | ||||
|      * the top of this file, near KRB5_SCACHE_DIR's definition. | ||||
|      */ | ||||
|     (void) chmod(s->file, 0600); | ||||
| #endif | ||||
|  | ||||
|     return 0; | ||||
|  | ||||
| out: | ||||
|   | ||||
| @@ -100,8 +100,6 @@ cleanup(void) | ||||
|     unlink_this2 = NULL; | ||||
|  | ||||
|     rmdir(tmpdir); | ||||
|     free(tmpdir); | ||||
|     tmpdir = NULL; | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -996,7 +994,25 @@ main(int argc, char **argv) | ||||
| #if 0 | ||||
|     test_init_vs_destroy(context, krb5_cc_type_api); | ||||
| #endif | ||||
|     /* | ||||
|      * Cleanup so we can check that the permissions on the directory created by | ||||
|      * scc are correct. | ||||
|      */ | ||||
|     cleanup(); | ||||
|     test_init_vs_destroy(context, krb5_cc_type_scc); | ||||
|  | ||||
| #if defined(S_IRWXG) && defined(S_IRWXO) | ||||
|     { | ||||
|         struct stat st; | ||||
|  | ||||
|         if (stat(tmpdir, &st) == 0) { | ||||
|             if ((st.st_mode & S_IRWXG) || | ||||
|                 (st.st_mode & S_IRWXO)) | ||||
|                 krb5_errx(context, 1, | ||||
|                           "SQLite3 ccache dir perms wrong: %d", st.st_mode); | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|     test_init_vs_destroy(context, krb5_cc_type_dcc); | ||||
| #ifdef HAVE_KEYUTILS_H | ||||
|     test_init_vs_destroy(context, krb5_cc_type_keyring); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Nicolas Williams
					Nicolas Williams