b3d375b2 |
1 | #include "putty.h" |
2 | |
3 | #include <string.h> |
4 | #include "sshgssc.h" |
5 | #include "misc.h" |
6 | |
7 | #ifndef NO_GSSAPI |
8 | |
9 | static Ssh_gss_stat ssh_gssapi_indicate_mech(struct ssh_gss_library *lib, |
10 | Ssh_gss_buf *mech) |
11 | { |
12 | /* Copy constant into mech */ |
13 | mech->length = GSS_MECH_KRB5->length; |
14 | mech->value = GSS_MECH_KRB5->elements; |
15 | return SSH_GSS_OK; |
16 | } |
17 | |
18 | static Ssh_gss_stat ssh_gssapi_import_name(struct ssh_gss_library *lib, |
19 | char *host, |
20 | Ssh_gss_name *srv_name) |
21 | { |
22 | struct gssapi_functions *gss = &lib->u.gssapi; |
23 | OM_uint32 min_stat,maj_stat; |
24 | gss_buffer_desc host_buf; |
25 | char *pStr; |
26 | |
27 | pStr = dupcat("host@", host, NULL); |
28 | |
29 | host_buf.value = pStr; |
30 | host_buf.length = strlen(pStr); |
31 | |
32 | maj_stat = gss->import_name(&min_stat, &host_buf, |
33 | GSS_C_NT_HOSTBASED_SERVICE, srv_name); |
34 | /* Release buffer */ |
35 | sfree(pStr); |
36 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; |
37 | return SSH_GSS_FAILURE; |
38 | } |
39 | |
40 | static Ssh_gss_stat ssh_gssapi_acquire_cred(struct ssh_gss_library *lib, |
41 | Ssh_gss_ctx *ctx) |
42 | { |
43 | gssapi_ssh_gss_ctx *gssctx = snew(gssapi_ssh_gss_ctx); |
44 | |
45 | gssctx->maj_stat = gssctx->min_stat = GSS_S_COMPLETE; |
46 | gssctx->ctx = GSS_C_NO_CONTEXT; |
47 | *ctx = (Ssh_gss_ctx) gssctx; |
48 | |
49 | return SSH_GSS_OK; |
50 | } |
51 | |
52 | static Ssh_gss_stat ssh_gssapi_init_sec_context(struct ssh_gss_library *lib, |
53 | Ssh_gss_ctx *ctx, |
54 | Ssh_gss_name srv_name, |
55 | int to_deleg, |
56 | Ssh_gss_buf *recv_tok, |
57 | Ssh_gss_buf *send_tok) |
58 | { |
59 | struct gssapi_functions *gss = &lib->u.gssapi; |
60 | gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx*) *ctx; |
61 | OM_uint32 ret_flags; |
62 | |
63 | if (to_deleg) to_deleg = GSS_C_DELEG_FLAG; |
64 | gssctx->maj_stat = gss->init_sec_context(&gssctx->min_stat, |
65 | GSS_C_NO_CREDENTIAL, |
66 | &gssctx->ctx, |
67 | srv_name, |
68 | (gss_OID) GSS_MECH_KRB5, |
69 | GSS_C_MUTUAL_FLAG | |
70 | GSS_C_INTEG_FLAG | to_deleg, |
71 | 0, |
72 | GSS_C_NO_CHANNEL_BINDINGS, |
73 | recv_tok, |
74 | NULL, /* ignore mech type */ |
75 | send_tok, |
76 | &ret_flags, |
77 | NULL); /* ignore time_rec */ |
78 | |
79 | if (gssctx->maj_stat == GSS_S_COMPLETE) return SSH_GSS_S_COMPLETE; |
80 | if (gssctx->maj_stat == GSS_S_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED; |
81 | return SSH_GSS_FAILURE; |
82 | } |
83 | |
84 | static Ssh_gss_stat ssh_gssapi_display_status(struct ssh_gss_library *lib, |
85 | Ssh_gss_ctx ctx, |
86 | Ssh_gss_buf *buf) |
87 | { |
88 | struct gssapi_functions *gss = &lib->u.gssapi; |
89 | gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) ctx; |
90 | OM_uint32 lmin,lmax; |
91 | OM_uint32 ccc; |
92 | gss_buffer_desc msg_maj=GSS_C_EMPTY_BUFFER; |
93 | gss_buffer_desc msg_min=GSS_C_EMPTY_BUFFER; |
94 | |
95 | /* Return empty buffer in case of failure */ |
96 | SSH_GSS_CLEAR_BUF(buf); |
97 | |
98 | /* get first mesg from GSS */ |
99 | ccc=0; |
100 | lmax=gss->display_status(&lmin,gssctx->maj_stat,GSS_C_GSS_CODE,(gss_OID) GSS_MECH_KRB5,&ccc,&msg_maj); |
101 | |
102 | if (lmax != GSS_S_COMPLETE) return SSH_GSS_FAILURE; |
103 | |
104 | /* get first mesg from Kerberos */ |
105 | ccc=0; |
106 | lmax=gss->display_status(&lmin,gssctx->min_stat,GSS_C_MECH_CODE,(gss_OID) GSS_MECH_KRB5,&ccc,&msg_min); |
107 | |
108 | if (lmax != GSS_S_COMPLETE) { |
109 | gss->release_buffer(&lmin, &msg_maj); |
110 | return SSH_GSS_FAILURE; |
111 | } |
112 | |
113 | /* copy data into buffer */ |
114 | buf->length = msg_maj.length + msg_min.length + 1; |
115 | buf->value = snewn(buf->length + 1, char); |
116 | |
117 | /* copy mem */ |
118 | memcpy((char *)buf->value, msg_maj.value, msg_maj.length); |
119 | ((char *)buf->value)[msg_maj.length] = ' '; |
120 | memcpy((char *)buf->value + msg_maj.length + 1, msg_min.value, msg_min.length); |
121 | ((char *)buf->value)[buf->length] = 0; |
122 | /* free mem & exit */ |
123 | gss->release_buffer(&lmin, &msg_maj); |
124 | gss->release_buffer(&lmin, &msg_min); |
125 | return SSH_GSS_OK; |
126 | } |
127 | |
128 | static Ssh_gss_stat ssh_gssapi_free_tok(struct ssh_gss_library *lib, |
129 | Ssh_gss_buf *send_tok) |
130 | { |
131 | struct gssapi_functions *gss = &lib->u.gssapi; |
132 | OM_uint32 min_stat,maj_stat; |
133 | maj_stat = gss->release_buffer(&min_stat, send_tok); |
134 | |
135 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; |
136 | return SSH_GSS_FAILURE; |
137 | } |
138 | |
139 | static Ssh_gss_stat ssh_gssapi_release_cred(struct ssh_gss_library *lib, |
140 | Ssh_gss_ctx *ctx) |
141 | { |
142 | struct gssapi_functions *gss = &lib->u.gssapi; |
143 | gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) *ctx; |
144 | OM_uint32 min_stat; |
145 | OM_uint32 maj_stat=GSS_S_COMPLETE; |
146 | |
147 | if (gssctx == NULL) return SSH_GSS_FAILURE; |
148 | if (gssctx->ctx != GSS_C_NO_CONTEXT) |
149 | maj_stat = gss->delete_sec_context(&min_stat,&gssctx->ctx,GSS_C_NO_BUFFER); |
150 | sfree(gssctx); |
151 | |
152 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; |
153 | return SSH_GSS_FAILURE; |
154 | } |
155 | |
156 | |
157 | static Ssh_gss_stat ssh_gssapi_release_name(struct ssh_gss_library *lib, |
158 | Ssh_gss_name *srv_name) |
159 | { |
160 | struct gssapi_functions *gss = &lib->u.gssapi; |
161 | OM_uint32 min_stat,maj_stat; |
162 | maj_stat = gss->release_name(&min_stat, srv_name); |
163 | |
164 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; |
165 | return SSH_GSS_FAILURE; |
166 | } |
167 | |
168 | static Ssh_gss_stat ssh_gssapi_get_mic(struct ssh_gss_library *lib, |
169 | Ssh_gss_ctx ctx, Ssh_gss_buf *buf, |
170 | Ssh_gss_buf *hash) |
171 | { |
172 | struct gssapi_functions *gss = &lib->u.gssapi; |
173 | gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) ctx; |
174 | if (gssctx == NULL) return SSH_GSS_FAILURE; |
175 | return gss->get_mic(&(gssctx->min_stat), gssctx->ctx, 0, buf, hash); |
176 | } |
177 | |
178 | static Ssh_gss_stat ssh_gssapi_free_mic(struct ssh_gss_library *lib, |
179 | Ssh_gss_buf *hash) |
180 | { |
181 | /* On Unix this is the same freeing process as ssh_gssapi_free_tok. */ |
182 | return ssh_gssapi_free_tok(lib, hash); |
183 | } |
184 | |
185 | void ssh_gssapi_bind_fns(struct ssh_gss_library *lib) |
186 | { |
187 | lib->indicate_mech = ssh_gssapi_indicate_mech; |
188 | lib->import_name = ssh_gssapi_import_name; |
189 | lib->release_name = ssh_gssapi_release_name; |
190 | lib->init_sec_context = ssh_gssapi_init_sec_context; |
191 | lib->free_tok = ssh_gssapi_free_tok; |
192 | lib->acquire_cred = ssh_gssapi_acquire_cred; |
193 | lib->release_cred = ssh_gssapi_release_cred; |
194 | lib->get_mic = ssh_gssapi_get_mic; |
195 | lib->free_mic = ssh_gssapi_free_mic; |
196 | lib->display_status = ssh_gssapi_display_status; |
197 | } |
198 | |
199 | #else |
200 | |
201 | /* Dummy function so this source file defines something if NO_GSSAPI |
202 | is defined. */ |
203 | |
204 | int ssh_gssapi_init(void) |
205 | { |
206 | return 0; |
207 | } |
208 | |
209 | #endif |