#include "cifs_spnego.h"
#define CIFS_DEFAULT_KRB5_DIR "/tmp"
-#define CIFS_DEFAULT_KRB5_PREFIX "krb5cc_"
+#define CIFS_DEFAULT_KRB5_USER_DIR "/run/user/%U"
+#define CIFS_DEFAULT_KRB5_PREFIX "krb5cc"
#define CIFS_DEFAULT_KRB5_KEYTAB "/etc/krb5.keytab"
#define MAX_CCNAME_LEN PATH_MAX + 5
static int krb5cc_filter(const struct dirent *dirent)
{
- if (strstr(dirent->d_name, CIFS_DEFAULT_KRB5_PREFIX))
- return 1;
- else
- return 0;
+ /* subtract 1 for the null terminator */
+ return !strncmp(dirent->d_name, CIFS_DEFAULT_KRB5_PREFIX,
+ sizeof(CIFS_DEFAULT_KRB5_PREFIX) - 1);
}
static char *
if (ccname == NULL)
syslog(LOG_ERR, "Unable to allocate memory");
icfk_cleanup:
- my_creds.client = 0;
+ my_creds.client = (krb5_principal)0;
krb5_free_cred_contents(context, &my_creds);
if (me)
return ccname;
}
+/* resolve a pattern to an actual directory path */
+static char *resolve_krb5_dir(const char *pattern, uid_t uid)
+{
+ char name[MAX_CCNAME_LEN];
+ int i;
+ size_t j;
+ for (i = 0, j = 0; (pattern[i] != '\0') && (j < sizeof(name)); i++) {
+ switch (pattern[i]) {
+ case '%':
+ switch (pattern[i + 1]) {
+ case '%':
+ name[j++] = pattern[i];
+ i++;
+ break;
+ case 'U':
+ j += snprintf(name + j, sizeof(name) - j,
+ "%lu", (unsigned long) uid);
+ i++;
+ break;
+ }
+ break;
+ default:
+ name[j++] = pattern[i];
+ break;
+ }
+ }
+ if ((j > 0) && (j < sizeof(name)))
+ return strndup(name, MAX_CCNAME_LEN);
+ else
+ return NULL;
+}
+
/* search for a credcache that looks like a likely candidate */
-static char *find_krb5_cc(const char *dirname, uid_t uid)
+static char *find_krb5_cc(const char *dirname, uid_t uid,
+ char **best_cache, time_t *best_time)
{
struct dirent **namelist;
struct stat sbuf;
- char ccname[MAX_CCNAME_LEN], *credpath, *best_cache = NULL;
+ char ccname[MAX_CCNAME_LEN], *credpath;
int i, n;
- time_t cred_time, best_time = 0;
+ time_t cred_time;
n = scandir(dirname, &namelist, krb5cc_filter, NULL);
if (n < 0) {
free(namelist[i]);
continue;
}
+ if (S_ISDIR(sbuf.st_mode)) {
+ snprintf(ccname, sizeof(ccname), "DIR:%s/%s", dirname,
+ namelist[i]->d_name);
+ credpath = ccname + 4;
+ } else
if (!S_ISREG(sbuf.st_mode)) {
syslog(LOG_DEBUG, "%s: %s is not a regular file",
__func__, credpath);
continue;
}
- if (cred_time <= best_time) {
+ if (cred_time <= *best_time) {
syslog(LOG_DEBUG, "%s: %s expires sooner than current "
"best.", __func__, ccname);
free(namelist[i]);
}
syslog(LOG_DEBUG, "%s: %s is valid ccache", __func__, ccname);
- free(best_cache);
- best_cache = strndup(ccname, MAX_CCNAME_LEN);
- best_time = cred_time;
+ free(*best_cache);
+ *best_cache = strndup(ccname, MAX_CCNAME_LEN);
+ *best_time = cred_time;
free(namelist[i]);
}
free(namelist);
- return best_cache;
+ return *best_cache;
}
static int
return ret;
}
- ret = krb5_cc_resolve(context, ccname, &ccache);
- if (ret) {
- syslog(LOG_DEBUG, "%s: unable to resolve %s to ccache\n",
- __func__, ccname);
- goto out_free_context;
+ if (ccname) {
+ ret = krb5_cc_resolve(context, ccname, &ccache);
+ if (ret) {
+ syslog(LOG_DEBUG, "%s: unable to resolve %s to ccache\n",
+ __func__, ccname);
+ goto out_free_context;
+ }
+ } else {
+ ret = krb5_cc_default(context, &ccache);
+ if (ret) {
+ syslog(LOG_DEBUG, "%s: krb5_cc_default: %d",
+ __func__, (int)ret);
+ goto out_free_context;
+ }
}
memset(&in_creds, 0, sizeof(in_creds));
*/
in_data.data = discard_const_p(char, gss_cksum);
in_data.length = 24;
+
+ /* MIT krb5 < 1.7 is missing the prototype, but still has the symbol */
+#if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE
+ krb5_error_code krb5_auth_con_set_req_cksumtype(
+ krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_cksumtype cksumtype);
+#endif
ret = krb5_auth_con_set_req_cksumtype(context, auth_context, 0x8003);
if (ret) {
syslog(LOG_DEBUG, "%s: unable to set 0x8003 checksum",
static void usage(void)
{
- fprintf(stderr, "Usage: %s [-k /path/to/krb5.conf] [-t] [-v] [-l] key_serial\n", prog);
+ fprintf(stderr, "Usage: %s [ -K /path/to/keytab] [-k /path/to/krb5.conf] [-t] [-v] [-l] key_serial\n", prog);
}
-const struct option long_options[] = {
+static const struct option long_options[] = {
{"krb5conf", 1, NULL, 'k'},
{"legacy-uid", 0, NULL, 'l'},
{"trust-dns", 0, NULL, 't'},
+ {"keytab", 1, NULL, 'K'},
{"version", 0, NULL, 'v'},
{NULL, 0, NULL, 0}
};
unsigned int have;
long rc = 1;
int c, try_dns = 0, legacy_uid = 0;
- char *buf, *ccname = NULL;
+ char *buf, *ccdir = NULL, *ccname = NULL, *best_cache = NULL;
char hostbuf[NI_MAXHOST], *host;
struct decoded_args arg;
const char *oid;
uid_t uid;
char *keytab_name = CIFS_DEFAULT_KRB5_KEYTAB;
+ time_t best_time = 0;
hostbuf[0] = '\0';
memset(&arg, 0, sizeof(arg));
openlog(prog, 0, LOG_DAEMON);
- while ((c = getopt_long(argc, argv, "ck:ltv", long_options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "ck:K:ltv", long_options, NULL)) != -1) {
switch (c) {
case 'c':
/* legacy option -- skip it */
goto out;
}
break;
+ case 'K':
+ keytab_name = optarg;
+ break;
case 'l':
legacy_uid++;
break;
case 'v':
+ rc = 0;
printf("version: %s\n", VERSION);
goto out;
default:
syslog(LOG_ERR, "setuid: %s", strerror(errno));
goto out;
}
- ccname = find_krb5_cc(CIFS_DEFAULT_KRB5_DIR, uid);
+ ccdir = resolve_krb5_dir(CIFS_DEFAULT_KRB5_USER_DIR, uid);
+ if (ccdir != NULL)
+ find_krb5_cc(ccdir, uid, &best_cache, &best_time);
+ ccname = find_krb5_cc(CIFS_DEFAULT_KRB5_DIR, uid, &best_cache,
+ &best_time);
+ SAFE_FREE(ccdir);
/* Couldn't find credcache? Try to use keytab */
if (ccname == NULL && arg.username != NULL)
break;
}
- if (rc)
+ if (rc) {
+ syslog(LOG_DEBUG, "Unable to obtain service ticket");
goto out;
+ }
- /* pack SecurityBLob and SessionKey into downcall packet */
+ /* pack SecurityBlob and SessionKey into downcall packet */
datalen =
sizeof(struct cifs_spnego_msg) + secblob.length + sess_key.length;
keydata = (struct cifs_spnego_msg *)calloc(sizeof(char), datalen);
* make sure the kernel doesn't hang it off of a searchable keyring
* and interfere with the next attempt to instantiate the key.
*/
- if (rc != 0 && key == 0)
+ if (rc != 0 && key == 0) {
+ syslog(LOG_DEBUG, "Negating key");
keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT);
+ }
data_blob_free(&secblob);
data_blob_free(&sess_key);
SAFE_FREE(ccname);
SAFE_FREE(arg.ip);
SAFE_FREE(arg.username);
SAFE_FREE(keydata);
+ syslog(LOG_DEBUG, "Exit status %ld", rc);
return rc;
}