1/*
2 * Copyright (c) 2011 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2011 Apple Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#import <stdio.h>
37
38#import <Foundation/Foundation.h>
39#import <Heimdal/krb5.h>
40#import <GSS/gssapi.h>
41#import <GSS/gssapi_plugin.h>
42
43#include <syslog.h>
44#include <assert.h>
45
46/**
47 * Icky code that prints the target name and replace the cred with another cred that hard coded in the module
48 */
49
50#define GSSC_MAGIC 0x47111147
51
52struct gsssel_ctx {
53    int magic;
54};
55
56static const char selectuser[] = "lha@KTH.SE";
57static const char *replacenames[] = {
58    "host@svn.h5l.org",
59    NULL
60};
61
62static gss_cred_id_t
63isc_replace_cred(gss_name_t target, gss_OID mech, gss_cred_id_t original_cred, OM_uint32 flags)
64{
65    OM_uint32 maj_stat, min_stat;
66    gss_buffer_desc buffer;
67    gss_name_t name;
68    gss_cred_id_t newcred;
69    bool exchange = false;
70    size_t n;
71
72    /*
73     * Using gss_display_name() is wrong, however it the best we can
74     * do right now.
75     *
76     * We should use gss_import_name() and then compare the name with
77     * gss_compare_name(), the only issue with that is that comparing
78     * names fragile and do not work as expected wrt to case of
79     * string, and in case or Kerberos, hostbased service gets
80     * affected by realm.
81     */
82
83    maj_stat = gss_display_name(&min_stat, target, &buffer, NULL);
84    if (maj_stat == GSS_S_COMPLETE) {
85	syslog(LOG_ERR, "ISC-replace-cred target name: %.*s", (int)buffer.length, (char *)buffer.value);
86	for (n = 0; replacenames[n]; n++) {
87	    if (memmem(buffer.value, buffer.length, replacenames[n], strlen(replacenames[n])) != NULL)
88		exchange = true;
89	}
90	gss_release_buffer(&min_stat, &buffer);
91    }
92    if (!exchange) {
93	syslog(LOG_ERR, "ISC-replace-cred not replacing");
94	return NULL;
95    }
96
97    buffer.value = (char *)(uintptr_t)selectuser;
98    buffer.length = strlen(selectuser);
99    maj_stat = gss_import_name(&min_stat, &buffer, GSS_C_NT_USER_NAME, &name);
100    if (maj_stat != GSS_S_COMPLETE)
101	return NULL;
102
103    maj_stat = gss_acquire_cred(&min_stat, name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_INITIATE,
104				&newcred, NULL, NULL);
105    gss_release_name(&min_stat, &name);
106    if (maj_stat != GSS_S_COMPLETE)
107	return NULL;
108
109    syslog(LOG_ERR, "ISC-replace-cred replacing cred to: %s", selectuser);
110
111    return newcred;
112}
113
114static krb5_error_code
115gsssel_init(krb5_context context, void **ptr)
116{
117    struct gsssel_ctx *ctx = calloc(1, sizeof(*ctx));
118
119    if (ctx == NULL)
120	return ENOMEM;
121
122    ctx->magic = GSSC_MAGIC;
123
124    *ptr = ctx;
125    return 0;
126}
127
128static void
129gsssel_fini(void *ptr)
130{
131    struct gsssel_ctx *ctx = ptr;
132
133    assert(ctx->magic == GSSC_MAGIC);
134
135    free(ctx);
136}
137
138
139gssapi_plugin_ftable gssapi_plugin = {
140    GSSAPI_PLUGIN_VERSION_1,
141    gsssel_init,
142    gsssel_fini,
143    "gssapi credential selector",
144    0,
145    isc_replace_cred
146};
147