1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/ccache/ccselect_k5identity.c - k5identity ccselect module */
4 * Copyright (C) 2011 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
29 #include <krb5/ccselect_plugin.h>
36 static krb5_error_code
37 k5identity_init(krb5_context context, krb5_ccselect_moddata *data_out,
41 *priority_out = KRB5_CCSELECT_PRIORITY_AUTHORITATIVE;
45 /* Match data (folded to lowercase if fold_case is set) against pattern. */
47 fnmatch_data(const char *pattern, krb5_data *data, krb5_boolean fold_case)
53 str = k5memdup0(data->data, data->length, &ret);
58 for (p = str; *p != '\0'; p++) {
59 if (isupper((unsigned char)*p))
60 *p = tolower((unsigned char)*p);
64 res = fnmatch(pattern, str, 0);
69 /* Return true if server satisfies the constraint given by name and value. */
71 check_constraint(krb5_context context, const char *name, const char *value,
72 krb5_principal server)
74 if (strcmp(name, "realm") == 0) {
75 return fnmatch_data(value, &server->realm, FALSE);
76 } else if (strcmp(name, "service") == 0) {
77 return (server->type == KRB5_NT_SRV_HST && server->length >= 2 &&
78 fnmatch_data(value, &server->data[0], FALSE));
79 } else if (strcmp(name, "host") == 0) {
80 return (server->type == KRB5_NT_SRV_HST && server->length >= 2 &&
81 fnmatch_data(value, &server->data[1], TRUE));
83 /* Assume unrecognized constraints are critical. */
88 * If line begins with a valid principal and server matches the constraints
89 * listed afterwards, set *princ_out to the client principal described in line
90 * and return true. Otherwise return false. May destructively affect line.
93 parse_line(krb5_context context, char *line, krb5_principal server,
94 krb5_principal *princ_out)
96 const char *whitespace = " \t\r\n";
97 char *princ, *princ_end, *field, *field_end, *sep;
101 /* Find the bounds of the principal. */
102 princ = line + strspn(line, whitespace);
105 princ_end = princ + strcspn(princ, whitespace);
106 if (princ_end == princ)
109 /* Check all constraints. */
110 field = princ_end + strspn(princ_end, whitespace);
111 while (*field != '\0') {
112 field_end = field + strcspn(field, whitespace);
113 if (*field_end != '\0')
115 sep = strchr(field, '=');
116 if (sep == NULL) /* Malformed line. */
119 if (!check_constraint(context, field, sep + 1, server))
121 field = field_end + strspn(field_end, whitespace);
125 return (krb5_parse_name(context, princ, princ_out) == 0);
128 /* Determine the current user's homedir. Allow HOME to override the result for
129 * non-secure profiles; otherwise, use the euid's homedir from passwd. */
131 get_homedir(krb5_context context)
133 const char *homedir = NULL;
135 struct passwd pwx, *pwd;
137 if (!context->profile_secure)
138 homedir = getenv("HOME");
140 if (homedir == NULL) {
141 if (k5_getpwuid_r(geteuid(), &pwx, pwbuf, sizeof(pwbuf), &pwd) != 0)
143 homedir = pwd->pw_dir;
146 return strdup(homedir);
149 static krb5_error_code
150 k5identity_choose(krb5_context context, krb5_ccselect_moddata data,
151 krb5_principal server, krb5_ccache *cache_out,
152 krb5_principal *princ_out)
155 krb5_principal princ = NULL;
156 char *filename, *homedir;
163 /* Open the .k5identity file. */
164 homedir = get_homedir(context);
166 return KRB5_PLUGIN_NO_HANDLE;
167 ret = k5_path_join(homedir, ".k5identity", &filename);
171 fp = fopen(filename, "r");
174 return KRB5_PLUGIN_NO_HANDLE;
176 /* Look for a line with constraints matched by server. */
177 while (fgets(buf, sizeof(buf), fp) != NULL) {
178 if (parse_line(context, buf, server, &princ))
183 return KRB5_PLUGIN_NO_HANDLE;
185 /* Look for a ccache with the appropriate client principal. If we don't
186 * find out, set *princ_out to indicate the desired client principal. */
187 ret = krb5_cc_cache_match(context, princ, cache_out);
188 if (ret == 0 || ret == KRB5_CC_NOTFOUND)
191 krb5_free_principal(context, princ);
196 ccselect_k5identity_initvt(krb5_context context, int maj_ver, int min_ver,
197 krb5_plugin_vtable vtable)
199 krb5_ccselect_vtable vt;
202 return KRB5_PLUGIN_VER_NOTSUPP;
203 vt = (krb5_ccselect_vtable)vtable;
204 vt->name = "k5identity";
205 vt->init = k5identity_init;
206 vt->choose = k5identity_choose;
210 #endif /* not _WIN32 */