aboutsummaryrefslogtreecommitdiff
path: root/tools/plink/sshgssc.c
blob: 87e2236ab3a4f8ceceacc667fe11a8036e841126 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include "putty.h"

#include <string.h>
#include "sshgssc.h"
#include "misc.h"

#ifndef NO_GSSAPI

static Ssh_gss_stat ssh_gssapi_indicate_mech(struct ssh_gss_library *lib,
					     Ssh_gss_buf *mech)
{
    /* Copy constant into mech */
    mech->length  = GSS_MECH_KRB5->length;
    mech->value = GSS_MECH_KRB5->elements;
    return SSH_GSS_OK;
}

static Ssh_gss_stat ssh_gssapi_import_name(struct ssh_gss_library *lib,
					   char *host,
					   Ssh_gss_name *srv_name)
{
    struct gssapi_functions *gss = &lib->u.gssapi;
    OM_uint32 min_stat,maj_stat;
    gss_buffer_desc host_buf;
    char *pStr;

    pStr = dupcat("host@", host, NULL);

    host_buf.value = pStr;
    host_buf.length = strlen(pStr);

    maj_stat = gss->import_name(&min_stat, &host_buf,
				GSS_C_NT_HOSTBASED_SERVICE, srv_name);
    /* Release buffer */
    sfree(pStr);
    if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK;
    return SSH_GSS_FAILURE;
}

static Ssh_gss_stat ssh_gssapi_acquire_cred(struct ssh_gss_library *lib,
					    Ssh_gss_ctx *ctx)
{
    gssapi_ssh_gss_ctx *gssctx = snew(gssapi_ssh_gss_ctx);

    gssctx->maj_stat =  gssctx->min_stat = GSS_S_COMPLETE;
    gssctx->ctx = GSS_C_NO_CONTEXT;
    *ctx = (Ssh_gss_ctx) gssctx;

    return SSH_GSS_OK;
}

static Ssh_gss_stat ssh_gssapi_init_sec_context(struct ssh_gss_library *lib,
						Ssh_gss_ctx *ctx,
						Ssh_gss_name srv_name,
						int to_deleg,
						Ssh_gss_buf *recv_tok,
						Ssh_gss_buf *send_tok)
{
    struct gssapi_functions *gss = &lib->u.gssapi;
    gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx*) *ctx;
    OM_uint32 ret_flags;

    if (to_deleg) to_deleg = GSS_C_DELEG_FLAG;
    gssctx->maj_stat = gss->init_sec_context(&gssctx->min_stat,
					     GSS_C_NO_CREDENTIAL,
					     &gssctx->ctx,
					     srv_name,
					     (gss_OID) GSS_MECH_KRB5,
					     GSS_C_MUTUAL_FLAG |
					     GSS_C_INTEG_FLAG | to_deleg,
					     0,
					     GSS_C_NO_CHANNEL_BINDINGS,
					     recv_tok,
					     NULL,   /* ignore mech type */
					     send_tok,
					     &ret_flags,
					     NULL);  /* ignore time_rec */

    if (gssctx->maj_stat == GSS_S_COMPLETE) return SSH_GSS_S_COMPLETE;
    if (gssctx->maj_stat == GSS_S_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED;
    return SSH_GSS_FAILURE;
}

static Ssh_gss_stat ssh_gssapi_display_status(struct ssh_gss_library *lib,
					      Ssh_gss_ctx ctx,
					      Ssh_gss_buf *buf)
{
    struct gssapi_functions *gss = &lib->u.gssapi;
    gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) ctx;
    OM_uint32 lmin,lmax;
    OM_uint32 ccc;
    gss_buffer_desc msg_maj=GSS_C_EMPTY_BUFFER;
    gss_buffer_desc msg_min=GSS_C_EMPTY_BUFFER;

    /* Return empty buffer in case of failure */
    SSH_GSS_CLEAR_BUF(buf);

    /* get first mesg from GSS */
    ccc=0;
    lmax=gss->display_status(&lmin,gssctx->maj_stat,GSS_C_GSS_CODE,(gss_OID) GSS_MECH_KRB5,&ccc,&msg_maj);

    if (lmax != GSS_S_COMPLETE) return SSH_GSS_FAILURE;

    /* get first mesg from Kerberos */
    ccc=0;
    lmax=gss->display_status(&lmin,gssctx->min_stat,GSS_C_MECH_CODE,(gss_OID) GSS_MECH_KRB5,&ccc,&msg_min);

    if (lmax != GSS_S_COMPLETE) {
        gss->release_buffer(&lmin, &msg_maj);
        return SSH_GSS_FAILURE;
    }

    /* copy data into buffer */
    buf->length = msg_maj.length + msg_min.length + 1;
    buf->value = snewn(buf->length + 1, char);

    /* copy mem */
    memcpy((char *)buf->value, msg_maj.value, msg_maj.length);
    ((char *)buf->value)[msg_maj.length] = ' ';
    memcpy((char *)buf->value + msg_maj.length + 1, msg_min.value, msg_min.length);
    ((char *)buf->value)[buf->length] = 0;
    /* free mem & exit */
    gss->release_buffer(&lmin, &msg_maj);
    gss->release_buffer(&lmin, &msg_min);
    return SSH_GSS_OK;
}

static Ssh_gss_stat ssh_gssapi_free_tok(struct ssh_gss_library *lib,
					Ssh_gss_buf *send_tok)
{
    struct gssapi_functions *gss = &lib->u.gssapi;
    OM_uint32 min_stat,maj_stat;
    maj_stat = gss->release_buffer(&min_stat, send_tok);

    if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK;
    return SSH_GSS_FAILURE;
}

static Ssh_gss_stat ssh_gssapi_release_cred(struct ssh_gss_library *lib,
					    Ssh_gss_ctx *ctx)
{
    struct gssapi_functions *gss = &lib->u.gssapi;
    gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) *ctx;
    OM_uint32 min_stat;
    OM_uint32 maj_stat=GSS_S_COMPLETE;

    if (gssctx == NULL) return SSH_GSS_FAILURE;
    if (gssctx->ctx != GSS_C_NO_CONTEXT)
        maj_stat = gss->delete_sec_context(&min_stat,&gssctx->ctx,GSS_C_NO_BUFFER);
    sfree(gssctx);

    if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK;
    return SSH_GSS_FAILURE;
}


static Ssh_gss_stat ssh_gssapi_release_name(struct ssh_gss_library *lib,
					    Ssh_gss_name *srv_name)
{
    struct gssapi_functions *gss = &lib->u.gssapi;
    OM_uint32 min_stat,maj_stat;
    maj_stat = gss->release_name(&min_stat, srv_name);

    if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK;
    return SSH_GSS_FAILURE;
}

static Ssh_gss_stat ssh_gssapi_get_mic(struct ssh_gss_library *lib,
				       Ssh_gss_ctx ctx, Ssh_gss_buf *buf,
				       Ssh_gss_buf *hash)
{
    struct gssapi_functions *gss = &lib->u.gssapi;
    gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) ctx;
    if (gssctx == NULL) return SSH_GSS_FAILURE;
    return gss->get_mic(&(gssctx->min_stat), gssctx->ctx, 0, buf, hash);
}

static Ssh_gss_stat ssh_gssapi_free_mic(struct ssh_gss_library *lib,
					Ssh_gss_buf *hash)
{
    /* On Unix this is the same freeing process as ssh_gssapi_free_tok. */
    return ssh_gssapi_free_tok(lib, hash);
}

void ssh_gssapi_bind_fns(struct ssh_gss_library *lib)
{
    lib->indicate_mech = ssh_gssapi_indicate_mech;
    lib->import_name = ssh_gssapi_import_name;
    lib->release_name = ssh_gssapi_release_name;
    lib->init_sec_context = ssh_gssapi_init_sec_context;
    lib->free_tok = ssh_gssapi_free_tok;
    lib->acquire_cred = ssh_gssapi_acquire_cred;
    lib->release_cred = ssh_gssapi_release_cred;
    lib->get_mic = ssh_gssapi_get_mic;
    lib->free_mic = ssh_gssapi_free_mic;
    lib->display_status = ssh_gssapi_display_status;
}

#else

/* Dummy function so this source file defines something if NO_GSSAPI
   is defined. */

int ssh_gssapi_init(void)
{
    return 0;
}

#endif