]>
Commit | Line | Data |
---|---|---|
71f23813 | 1 | Add secinfo processing. |
97cc26d8 | 2 | |
71f23813 | 3 | From: Fred Isaman <iisaman@citi.umich.edu> |
97cc26d8 | 4 | |
71f23813 | 5 | Signed-off-by: Fred Isaman <iisaman@citi.umich.edu> |
97cc26d8 | 6 | |
71f23813 JR |
7 | Add secinfo processing. |
8 | --- | |
9 | ||
10 | support/include/nfslib.h | 6 ++ | |
11 | support/nfs/exports.c | 145 ++++++++++++++++++++++++++++++++++++++++++++- | |
12 | utils/exportfs/exportfs.c | 3 + | |
13 | utils/mountd/cache.c | 14 ++++ | |
14 | 4 files changed, 164 insertions(+), 4 deletions(-) | |
15 | ||
16 | Try to use kernel function to determine supported Kerberos enctypes. | |
97cc26d8 | 17 | |
71f23813 JR |
18 | From: Kevin Coffman <kwc@citi.umich.edu> |
19 | ||
20 | Signed-off-by: Kevin Coffman <kwc@citi.umich.edu> | |
21 | ||
22 | This patch replaces a hard-coded list with a function to obtain | |
23 | the Kerberos encryption types that the kernel's rpcsec_gss code | |
24 | can support. Defaults to old behavior if kernel does not supply | |
25 | information. | |
26 | --- | |
97cc26d8 | 27 | |
71f23813 JR |
28 | utils/gssd/gssd.c | 2 |
29 | utils/gssd/krb5_util.c | 228 +++++++++++++++++++++++++++++++++++++----------- | |
30 | utils/gssd/krb5_util.h | 2 | |
31 | 3 files changed, 182 insertions(+), 50 deletions(-) | |
97cc26d8 | 32 | |
71f23813 | 33 | Add EXPERIMENTAL support for non-DES encryption types. |
97cc26d8 | 34 | |
71f23813 | 35 | From: Kevin Coffman <kwc@citi.umich.edu> |
97cc26d8 | 36 | |
71f23813 | 37 | Signed-off-by: Kevin Coffman <kwc@citi.umich.edu> |
97cc26d8 | 38 | |
71f23813 JR |
39 | Adds EXPERIMENTAL support for non-DES encryption types. Sends a new |
40 | format of context information to the kernel. | |
41 | (Requires kernel support to do anything useful.) | |
97cc26d8 JB |
42 | --- |
43 | ||
71f23813 JR |
44 | utils/gssd/context.h | 6 + |
45 | utils/gssd/context_lucid.c | 391 ++++++++++++++++++++++++++++++++++++++++++-- | |
46 | utils/gssd/context_mit.c | 254 +++++++++++++++++++++++++---- | |
47 | 3 files changed, 603 insertions(+), 48 deletions(-) | |
97cc26d8 | 48 | |
71f23813 JR |
49 | diff --git a/support/include/nfslib.h b/support/include/nfslib.h |
50 | index c085029..6d7743d 100644 | |
51 | --- a/support/include/nfslib.h | |
52 | +++ b/support/include/nfslib.h | |
53 | @@ -57,6 +57,9 @@ enum cle_maptypes { | |
54 | #define _PATH_PROC_EXPORTS_ALT "/proc/fs/nfsd/exports" | |
55 | #endif | |
97cc26d8 | 56 | |
71f23813 JR |
57 | +#define SECFLAVOR_COUNT 7 |
58 | +extern char *secflavor_name[SECFLAVOR_COUNT]; | |
97cc26d8 | 59 | + |
71f23813 JR |
60 | /* |
61 | * Data related to a single exports entry as returned by getexportent. | |
62 | * FIXME: export options should probably be parsed at a later time to | |
63 | @@ -83,6 +86,8 @@ struct exportent { | |
64 | int e_fslocmethod; | |
65 | char * e_fslocdata; | |
66 | char * e_uuid; | |
67 | + int e_secinfo_order[SECFLAVOR_COUNT+1]; | |
68 | + int e_secinfo_flags[SECFLAVOR_COUNT]; | |
69 | }; | |
70 | ||
71 | struct rmtabent { | |
72 | @@ -96,6 +101,7 @@ struct rmtabent { | |
73 | */ | |
74 | void setexportent(char *fname, char *type); | |
75 | struct exportent * getexportent(int,int); | |
76 | +void secinfo_show(FILE *fp, struct exportent *ep); | |
77 | void putexportent(struct exportent *xep); | |
78 | void endexportent(void); | |
79 | struct exportent * mkexportent(char *hname, char *path, char *opts); | |
80 | diff --git a/support/nfs/exports.c b/support/nfs/exports.c | |
81 | index 294e1c9..af9ab2f 100644 | |
82 | --- a/support/nfs/exports.c | |
83 | +++ b/support/nfs/exports.c | |
84 | @@ -51,6 +51,10 @@ static int parsenum(char **cpp); | |
85 | static int parsenum(char **cpp); | |
97cc26d8 JB |
86 | static void freesquash(void); |
87 | static void syntaxerr(char *msg); | |
88 | +static unsigned int parse_flavors(char *str, struct exportent *ep); | |
89 | +static int secinfo_default(struct exportent *ep); | |
90 | +static void setflags(int mask, unsigned int *ap, struct exportent *ep); | |
91 | +static void clearflags(int mask, unsigned int *ap, struct exportent *ep); | |
92 | ||
93 | void | |
94 | setexportent(char *fname, char *type) | |
71f23813 | 95 | @@ -102,6 +106,7 @@ getexportent(int fromkernel, int fromexp |
97cc26d8 JB |
96 | def_ee.e_mountpoint = NULL; |
97 | def_ee.e_fslocmethod = FSLOC_NONE; | |
98 | def_ee.e_fslocdata = NULL; | |
99 | + def_ee.e_secinfo_order[0] = -1; | |
100 | def_ee.e_nsquids = 0; | |
101 | def_ee.e_nsqgids = 0; | |
102 | ||
71f23813 | 103 | @@ -182,6 +187,19 @@ getexportent(int fromkernel, int fromexp |
97cc26d8 JB |
104 | } |
105 | ||
106 | void | |
107 | +secinfo_show(FILE *fp, struct exportent *ep) | |
108 | +{ | |
109 | + int *p1, *p2; | |
110 | + for (p1=ep->e_secinfo_order; *p1>=0; p1=p2) { | |
111 | + fprintf(fp, ",sec=%s", secflavor_name[*p1]); | |
112 | + for (p2=p1+1; (*p2>=0) && (ep->e_secinfo_flags[*p1]==ep->e_secinfo_flags[*p2]); p2++) { | |
113 | + fprintf(fp, ":%s", secflavor_name[*p2]); | |
114 | + } | |
115 | + fprintf(fp, ",%s", (ep->e_secinfo_flags[*p1] & NFSEXP_READONLY)? "ro" : "rw"); | |
116 | + } | |
117 | +} | |
118 | + | |
119 | +void | |
120 | putexportent(struct exportent *ep) | |
121 | { | |
122 | FILE *fp; | |
71f23813 | 123 | @@ -199,7 +217,6 @@ putexportent(struct exportent *ep) |
97cc26d8 JB |
124 | fprintf(fp, "%c", esc[i]); |
125 | ||
126 | fprintf(fp, "\t%s(", ep->e_hostname); | |
127 | - fprintf(fp, "%s,", (ep->e_flags & NFSEXP_READONLY)? "ro" : "rw"); | |
128 | fprintf(fp, "%ssync,", (ep->e_flags & NFSEXP_ASYNC)? "a" : ""); | |
129 | fprintf(fp, "%swdelay,", (ep->e_flags & NFSEXP_GATHERED_WRITES)? | |
130 | "" : "no_"); | |
71f23813 | 131 | @@ -276,7 +293,9 @@ #endif |
97cc26d8 JB |
132 | else |
133 | fprintf(fp, "%d,", id[i]); | |
134 | } | |
135 | - fprintf(fp, "anonuid=%d,anongid=%d)\n", ep->e_anonuid, ep->e_anongid); | |
136 | + fprintf(fp, "anonuid=%d,anongid=%d", ep->e_anonuid, ep->e_anongid); | |
137 | + secinfo_show(fp, ep); | |
138 | + fprintf(fp, ")\n"); | |
139 | } | |
140 | ||
141 | void | |
71f23813 | 142 | @@ -325,6 +344,7 @@ mkexportent(char *hname, char *path, cha |
97cc26d8 JB |
143 | ee.e_mountpoint = NULL; |
144 | ee.e_fslocmethod = FSLOC_NONE; | |
145 | ee.e_fslocdata = NULL; | |
146 | + ee.e_secinfo_order[0] = -1; | |
147 | ee.e_nsquids = 0; | |
148 | ee.e_nsqgids = 0; | |
149 | ee.e_uuid = NULL; | |
71f23813 | 150 | @@ -376,6 +396,9 @@ parseopts(char *cp, struct exportent *ep |
97cc26d8 JB |
151 | int had_subtree_opt = 0; |
152 | char *flname = efname?efname:"command line"; | |
153 | int flline = efp?efp->x_line:0; | |
154 | + int *p; | |
155 | + unsigned int active = 0; | |
156 | + int secmask = NFSEXP_READONLY; /* options that can vary per flavor */ | |
157 | ||
158 | squids = ep->e_squids; nsquids = ep->e_nsquids; | |
159 | sqgids = ep->e_sqgids; nsqgids = ep->e_nsqgids; | |
71f23813 | 160 | @@ -398,9 +421,9 @@ parseopts(char *cp, struct exportent *ep |
97cc26d8 JB |
161 | |
162 | /* process keyword */ | |
163 | if (strcmp(opt, "ro") == 0) | |
164 | - ep->e_flags |= NFSEXP_READONLY; | |
165 | + setflags(NFSEXP_READONLY, &active, ep); | |
166 | else if (strcmp(opt, "rw") == 0) | |
167 | - ep->e_flags &= ~NFSEXP_READONLY; | |
168 | + clearflags(NFSEXP_READONLY, &active, ep); | |
169 | else if (!strcmp(opt, "secure")) | |
170 | ep->e_flags &= ~NFSEXP_INSECURE_PORT; | |
171 | else if (!strcmp(opt, "insecure")) | |
71f23813 | 172 | @@ -522,6 +545,10 @@ #endif |
97cc26d8 JB |
173 | } else if (strncmp(opt, "replicas=", 9) == 0) { |
174 | ep->e_fslocmethod = FSLOC_REPLICA; | |
175 | ep->e_fslocdata = strdup(opt+9); | |
176 | + } else if (strncmp(opt, "sec=", 4) == 0) { | |
177 | + active = parse_flavors(opt+4, ep); | |
178 | + if (!active) | |
179 | + goto bad_option; | |
180 | } else { | |
181 | xlog(L_ERROR, "%s:%d: unknown keyword \"%s\"\n", | |
182 | flname, flline, opt); | |
71f23813 | 183 | @@ -533,6 +560,12 @@ #endif |
97cc26d8 JB |
184 | cp++; |
185 | } | |
186 | ||
187 | + if (!active) | |
188 | + active = secinfo_default(ep); | |
189 | + for (p=ep->e_secinfo_order; *p>=0; p++) | |
190 | + ep->e_secinfo_flags[*p] |= (ep->e_flags & ~secmask); | |
191 | + /* If did not use sec= option, ensure e_flags is backward compatible */ | |
192 | + ep->e_flags = ep->e_secinfo_flags[ep->e_secinfo_order[0]]; | |
193 | ep->e_squids = squids; | |
194 | ep->e_sqgids = sqgids; | |
195 | ep->e_nsquids = nsquids; | |
71f23813 | 196 | @@ -663,3 +696,107 @@ syntaxerr(char *msg) |
97cc26d8 JB |
197 | efname, efp?efp->x_line:0, msg); |
198 | } | |
199 | ||
200 | +char *secflavor_name[SECFLAVOR_COUNT] = { "sys", | |
201 | + "krb5", | |
202 | + "krb5i", | |
203 | + "krb5p", | |
204 | + "spkm3", | |
205 | + "spkm3i", | |
206 | + "spkm3p" | |
207 | +}; | |
208 | + | |
209 | +static void | |
210 | +secinfo_addflavor(int bit, struct exportent *ep) | |
211 | +{ | |
212 | + int *p; | |
213 | + for (p=ep->e_secinfo_order; *p>=0; p++) { | |
214 | + if (*p == bit) | |
215 | + return; | |
216 | + } | |
217 | + *p++ = bit; | |
218 | + *p = -1; | |
219 | + ep->e_secinfo_flags[bit] = 0; | |
220 | +} | |
221 | + | |
222 | +static int | |
223 | +secinfo_nameindex(char *name) | |
224 | +{ | |
225 | + int i; | |
226 | + for (i=0; i<SECFLAVOR_COUNT; i++) { | |
227 | + if (strcmp(secflavor_name[i], name) == 0) | |
228 | + return i; | |
229 | + } | |
230 | + return -1; | |
231 | +} | |
232 | + | |
233 | +/* @str is a colon seperated list of security flavors. Their order | |
234 | + * is recorded in @ep, and a bitmap corresponding to the list is returned. | |
235 | + * A zero return indicates an error. | |
236 | + */ | |
237 | +static unsigned int | |
238 | +parse_flavors(char *str, struct exportent *ep) | |
239 | +{ | |
240 | + unsigned int out=0; | |
241 | + char *flavor; | |
242 | + int bit; | |
243 | + | |
244 | + while ( (flavor=strsep(&str, ":")) ) { | |
245 | + bit = secinfo_nameindex(flavor); | |
246 | + if (bit == -1) { | |
247 | + xlog(L_ERROR, "unknown flavor %s\n", flavor); | |
248 | + return 0; | |
249 | + } | |
250 | + out |= 1<<bit; | |
251 | + secinfo_addflavor(bit, ep); | |
252 | + } | |
253 | + return out; | |
254 | +} | |
255 | + | |
256 | +/* Determine a default security flavor based on ep->e_hostname. */ | |
257 | +static int | |
258 | +secinfo_default(struct exportent *ep) | |
259 | +{ | |
260 | + int i=-1; | |
261 | + if (strncmp(ep->e_hostname, "gss/", 4) == 0) { | |
262 | + i = secinfo_nameindex(ep->e_hostname + 4); | |
263 | + if (i < 0) | |
264 | + xlog(L_WARNING, "unknown flavor %s\n", ep->e_hostname); | |
265 | + } | |
266 | + /* Default to auth_sys */ | |
267 | + if (i < 0) | |
268 | + i = secinfo_nameindex("sys"); | |
269 | + secinfo_addflavor(i, ep); | |
270 | + return 1<<i; | |
271 | +} | |
272 | + | |
273 | +/* Sets the bits in @mask for the appropriate security flavor flags. */ | |
274 | +static void | |
275 | +setflags(int mask, unsigned int *ap, struct exportent *ep) | |
276 | +{ | |
277 | + int active, flavor=0; | |
278 | + if (!*ap) | |
279 | + *ap = secinfo_default(ep); | |
280 | + active = *ap; | |
281 | + while (active) { | |
282 | + if (active & 1) | |
283 | + ep->e_secinfo_flags[flavor] |= mask; | |
284 | + flavor++; | |
285 | + active >>= 1; | |
286 | + } | |
287 | +} | |
288 | + | |
289 | +/* Clears the bits in @mask for the appropriate security flavor flags. */ | |
290 | +static void | |
291 | +clearflags(int mask, unsigned int *ap, struct exportent *ep) | |
292 | +{ | |
293 | + int active, flavor=0; | |
294 | + if (!*ap) | |
295 | + *ap = secinfo_default(ep); | |
296 | + active = *ap; | |
297 | + while (active) { | |
298 | + if (active & 1) | |
299 | + ep->e_secinfo_flags[flavor] &= ~mask; | |
300 | + flavor++; | |
301 | + active >>= 1; | |
302 | + } | |
303 | +} | |
71f23813 JR |
304 | diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c |
305 | index 22e13a3..30732b8 100644 | |
306 | --- a/utils/exportfs/exportfs.c | |
307 | +++ b/utils/exportfs/exportfs.c | |
308 | @@ -376,10 +376,12 @@ dump(int verbose) | |
97cc26d8 JB |
309 | continue; |
310 | } | |
311 | c = '('; | |
312 | + /* | |
313 | if (ep->e_flags & NFSEXP_READONLY) | |
314 | c = dumpopt(c, "ro"); | |
315 | else | |
316 | c = dumpopt(c, "rw"); | |
317 | + */ | |
318 | if (ep->e_flags & NFSEXP_ASYNC) | |
319 | c = dumpopt(c, "async"); | |
320 | if (ep->e_flags & NFSEXP_GATHERED_WRITES) | |
71f23813 | 321 | @@ -433,6 +435,7 @@ #ifdef DEBUG |
97cc26d8 JB |
322 | break; |
323 | #endif | |
324 | } | |
325 | + secinfo_show(stdout, ep); | |
326 | printf("%c\n", (c != '(')? ')' : ' '); | |
327 | } | |
328 | } | |
71f23813 JR |
329 | diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c |
330 | index 5f0d12a..78a8f75 100644 | |
331 | --- a/utils/mountd/cache.c | |
332 | +++ b/utils/mountd/cache.c | |
333 | @@ -445,6 +445,19 @@ static void write_fsloc(FILE *f, struct | |
334 | release_replicas(servers); | |
97cc26d8 JB |
335 | } |
336 | ||
71f23813 | 337 | +static void write_secinfo(FILE *f, struct exportent *ep) |
97cc26d8 | 338 | +{ |
71f23813 JR |
339 | + int *p; |
340 | + qword_print(f, "secinfo"); | |
341 | + for (p=ep->e_secinfo_order; *p>=0; p++) | |
342 | + ; /* Do nothing */ | |
343 | + qword_printint(f, p - ep->e_secinfo_order); | |
344 | + for (p=ep->e_secinfo_order; *p>=0; p++) { | |
345 | + qword_print(f, secflavor_name[*p]); | |
346 | + qword_printint(f, ep->e_secinfo_flags[*p]); | |
97cc26d8 | 347 | + } |
97cc26d8 JB |
348 | +} |
349 | + | |
71f23813 | 350 | static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *exp) |
97cc26d8 | 351 | { |
71f23813 JR |
352 | qword_print(f, domain); |
353 | @@ -466,6 +479,7 @@ static int dump_to_cache(FILE *f, char * | |
354 | qword_printhex(f, exp->e_uuid, 16); | |
355 | } | |
97cc26d8 | 356 | #endif |
71f23813 | 357 | + write_secinfo(f, exp); |
97cc26d8 | 358 | } |
71f23813 | 359 | return qword_eol(f); |
97cc26d8 | 360 | } |
71f23813 JR |
361 | diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c |
362 | index 08a6c10..44afdd0 100644 | |
363 | --- a/utils/gssd/gssd.c | |
364 | +++ b/utils/gssd/gssd.c | |
365 | @@ -162,6 +162,8 @@ #endif | |
97cc26d8 | 366 | /* Process keytab file and get machine credentials */ |
71f23813 JR |
367 | if (root_uses_machine_creds) |
368 | gssd_refresh_krb5_machine_creds(); | |
97cc26d8 JB |
369 | + /* Determine Kerberos information from the kernel */ |
370 | + gssd_obtain_kernel_krb5_info(); | |
371 | ||
372 | gssd_run(); | |
373 | printerr(0, "gssd_run returned!\n"); | |
71f23813 JR |
374 | diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c |
375 | index 096f6cf..96e91ae 100644 | |
376 | --- a/utils/gssd/krb5_util.c | |
377 | +++ b/utils/gssd/krb5_util.c | |
378 | @@ -97,6 +97,7 @@ #endif | |
97cc26d8 JB |
379 | #include "config.h" |
380 | #include <sys/param.h> | |
381 | #include <rpc/rpc.h> | |
382 | +#include <sys/types.h> | |
383 | #include <sys/stat.h> | |
384 | #include <sys/socket.h> | |
385 | #include <arpa/inet.h> | |
71f23813 | 386 | @@ -105,6 +106,7 @@ #include <stdio.h> |
97cc26d8 JB |
387 | #include <stdlib.h> |
388 | #include <string.h> | |
389 | #include <dirent.h> | |
390 | +#include <fcntl.h> | |
391 | #include <errno.h> | |
392 | #include <time.h> | |
393 | #include <gssapi/gssapi.h> | |
71f23813 | 394 | @@ -123,6 +125,10 @@ #include "krb5_util.h" |
97cc26d8 JB |
395 | /* Global list of principals/cache file names for machine credentials */ |
396 | struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; | |
397 | ||
398 | +/* Encryption types supported by the kernel rpcsec_gss code */ | |
399 | +int num_krb5_enctypes = 0; | |
400 | +krb5_enctype *krb5_enctypes = NULL; | |
401 | + | |
402 | /*==========================*/ | |
403 | /*=== Internal routines ===*/ | |
404 | /*==========================*/ | |
405 | @@ -256,56 +262,6 @@ gssd_find_existing_krb5_ccache(uid_t uid | |
406 | } | |
407 | ||
408 | ||
409 | -#ifdef HAVE_SET_ALLOWABLE_ENCTYPES | |
410 | -/* | |
411 | - * this routine obtains a credentials handle via gss_acquire_cred() | |
412 | - * then calls gss_krb5_set_allowable_enctypes() to limit the encryption | |
413 | - * types negotiated. | |
414 | - * | |
415 | - * XXX Should call some function to determine the enctypes supported | |
416 | - * by the kernel. (Only need to do that once!) | |
417 | - * | |
418 | - * Returns: | |
419 | - * 0 => all went well | |
420 | - * -1 => there was an error | |
421 | - */ | |
422 | - | |
423 | -int | |
424 | -limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) | |
425 | -{ | |
426 | - u_int maj_stat, min_stat; | |
427 | - gss_cred_id_t credh; | |
428 | - gss_OID_set_desc desired_mechs; | |
429 | - krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC }; | |
430 | - int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); | |
431 | - | |
432 | - /* We only care about getting a krb5 cred */ | |
433 | - desired_mechs.count = 1; | |
434 | - desired_mechs.elements = &krb5oid; | |
435 | - | |
436 | - maj_stat = gss_acquire_cred(&min_stat, NULL, 0, | |
437 | - &desired_mechs, GSS_C_INITIATE, | |
438 | - &credh, NULL, NULL); | |
439 | - | |
440 | - if (maj_stat != GSS_S_COMPLETE) { | |
441 | - pgsserr("gss_acquire_cred", | |
442 | - maj_stat, min_stat, &krb5oid); | |
443 | - return -1; | |
444 | - } | |
445 | - | |
446 | - maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid, | |
447 | - num_enctypes, &enctypes); | |
448 | - if (maj_stat != GSS_S_COMPLETE) { | |
449 | - pgsserr("gss_set_allowable_enctypes", | |
450 | - maj_stat, min_stat, &krb5oid); | |
451 | - return -1; | |
452 | - } | |
453 | - sec->cred = credh; | |
454 | - | |
455 | - return 0; | |
456 | -} | |
457 | -#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */ | |
458 | - | |
459 | /* | |
460 | * Obtain credentials via a key in the keytab given | |
461 | * a keytab handle and a gssd_k5_kt_princ structure. | |
71f23813 | 462 | @@ -609,6 +565,56 @@ #else |
97cc26d8 JB |
463 | #endif |
464 | } | |
465 | ||
466 | +/* | |
467 | + * Parse the supported encryption type information | |
468 | + */ | |
469 | +static int | |
470 | +parse_enctypes(char *enctypes) | |
471 | +{ | |
472 | + int n = 0; | |
473 | + char *curr, *comma; | |
474 | + int i; | |
475 | + | |
476 | + /* Just in case this ever gets called more than once */ | |
477 | + if (krb5_enctypes != NULL) { | |
478 | + free(krb5_enctypes); | |
479 | + krb5_enctypes = NULL; | |
480 | + num_krb5_enctypes = 0; | |
481 | + } | |
482 | + | |
483 | + /* count the number of commas */ | |
484 | + for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) { | |
485 | + comma = strchr(curr, ','); | |
486 | + if (comma != NULL) | |
487 | + n++; | |
488 | + else | |
489 | + break; | |
490 | + } | |
491 | + /* If no more commas and we're not at the end, there's one more value */ | |
492 | + if (*curr != '\0') | |
493 | + n++; | |
494 | + | |
495 | + /* Empty string, return an error */ | |
496 | + if (n == 0) | |
497 | + return ENOENT; | |
498 | + | |
499 | + /* Allocate space for enctypes array */ | |
500 | + if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) { | |
501 | + return ENOMEM; | |
502 | + } | |
503 | + | |
504 | + /* Now parse each value into the array */ | |
505 | + for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) { | |
506 | + krb5_enctypes[i++] = atoi(curr); | |
507 | + comma = strchr(curr, ','); | |
508 | + if (comma == NULL) | |
509 | + break; | |
510 | + } | |
511 | + | |
512 | + num_krb5_enctypes = n; | |
513 | + return 0; | |
514 | +} | |
515 | + | |
516 | /*==========================*/ | |
517 | /*=== External routines ===*/ | |
518 | /*==========================*/ | |
519 | @@ -860,3 +866,125 @@ gssd_destroy_krb5_machine_creds(void) | |
520 | krb5_free_context(context); | |
521 | } | |
522 | ||
523 | +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES | |
524 | +/* | |
525 | + * this routine obtains a credentials handle via gss_acquire_cred() | |
526 | + * then calls gss_krb5_set_allowable_enctypes() to limit the encryption | |
527 | + * types negotiated. | |
528 | + * | |
529 | + * Returns: | |
530 | + * 0 => all went well | |
531 | + * -1 => there was an error | |
532 | + */ | |
533 | + | |
534 | +int | |
535 | +limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) | |
536 | +{ | |
537 | + u_int maj_stat, min_stat; | |
538 | + gss_cred_id_t credh; | |
539 | + gss_OID_set_desc desired_mechs; | |
540 | + krb5_enctype enctypes[] = {ENCTYPE_DES_CBC_CRC}; | |
541 | + int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); | |
542 | + | |
543 | + /* We only care about getting a krb5 cred */ | |
544 | + desired_mechs.count = 1; | |
545 | + desired_mechs.elements = &krb5oid; | |
546 | + | |
547 | + maj_stat = gss_acquire_cred(&min_stat, NULL, 0, | |
548 | + &desired_mechs, GSS_C_INITIATE, | |
549 | + &credh, NULL, NULL); | |
550 | + | |
551 | + if (maj_stat != GSS_S_COMPLETE) { | |
552 | + pgsserr("gss_acquire_cred", | |
553 | + maj_stat, min_stat, &krb5oid); | |
554 | + return -1; | |
555 | + } | |
556 | + | |
557 | + /* | |
558 | + * If we failed for any reason to produce global | |
559 | + * list of supported enctypes, use local default here. | |
560 | + */ | |
561 | + if (krb5_enctypes == NULL) | |
562 | + maj_stat = gss_set_allowable_enctypes(&min_stat, credh, | |
563 | + &krb5oid, num_enctypes, &enctypes); | |
564 | + else | |
565 | + maj_stat = gss_set_allowable_enctypes(&min_stat, credh, | |
566 | + &krb5oid, num_krb5_enctypes, | |
567 | + krb5_enctypes); | |
568 | + if (maj_stat != GSS_S_COMPLETE) { | |
569 | + pgsserr("gss_set_allowable_enctypes", | |
570 | + maj_stat, min_stat, &krb5oid); | |
571 | + return -1; | |
572 | + } | |
573 | + sec->cred = credh; | |
574 | + | |
575 | + return 0; | |
576 | +} | |
577 | +#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */ | |
578 | + | |
579 | +/* | |
580 | + * Obtain supported enctypes from kernel. | |
581 | + * Set defaults if info is not available. | |
582 | + */ | |
583 | +void | |
584 | +gssd_obtain_kernel_krb5_info(void) | |
585 | +{ | |
586 | + char enctype_file_name[128]; | |
587 | + char buf[1024]; | |
588 | + char enctypes[128]; | |
589 | + int nscanned; | |
590 | + int fd; | |
591 | + int use_default_enctypes = 0; | |
592 | + int nbytes, numfields; | |
593 | + char default_enctypes[] = "1,3,2"; | |
594 | + int code; | |
595 | + | |
596 | + snprintf(enctype_file_name, sizeof(enctype_file_name), | |
597 | + "%s/%s", pipefs_dir, "krb5_info"); | |
598 | + | |
599 | + if ((fd = open(enctype_file_name, O_RDONLY)) == -1) { | |
600 | + printerr(1, "WARNING: gssd_obtain_kernel_krb5_info: " | |
601 | + "Unable to open '%s'. Unable to determine " | |
602 | + "Kerberos encryption types supported by the " | |
603 | + "kernel; using defaults (%s).\n", | |
604 | + enctype_file_name, default_enctypes); | |
605 | + use_default_enctypes = 1; | |
606 | + goto do_the_parse; | |
607 | + } | |
608 | + memset(buf, 0, sizeof(buf)); | |
609 | + if ((nbytes = read(fd, buf, sizeof(buf)-1)) == -1) { | |
610 | + printerr(0, "WARNING: gssd_obtain_kernel_krb5_info: " | |
611 | + "Error reading Kerberos encryption type " | |
612 | + "information file '%s'; using defaults (%s).\n", | |
613 | + enctype_file_name, default_enctypes); | |
614 | + use_default_enctypes = 1; | |
615 | + close(fd); | |
616 | + goto do_the_parse; | |
617 | + } | |
618 | + close(fd); | |
619 | + numfields = sscanf(buf, "enctypes: %s\n%n", enctypes, &nscanned); | |
620 | + if (numfields < 1) { | |
621 | + printerr(0, "WARNING: gssd_obtain_kernel_krb5_info: " | |
622 | + "error parsing Kerberos encryption type " | |
623 | + "information from file '%s'; using defaults (%s).\n", | |
624 | + enctype_file_name, default_enctypes); | |
625 | + use_default_enctypes = 1; | |
626 | + goto do_the_parse; | |
627 | + } | |
628 | + if (nbytes > nscanned) { | |
629 | + printerr(2, "gssd_obtain_kernel_krb5_info: " | |
630 | + "Ignoring extra information, '%s', from '%s'\n", | |
631 | + buf+nscanned, enctype_file_name); | |
632 | + goto do_the_parse; | |
633 | + } | |
634 | + do_the_parse: | |
635 | + if (use_default_enctypes) | |
636 | + strcpy(enctypes, default_enctypes); | |
637 | + | |
638 | + if ((code = parse_enctypes(enctypes)) != 0) { | |
639 | + printerr(0, "ERROR: gssd_obtain_kernel_krb5_info: " | |
640 | + "parse_enctypes%s failed with code %d\n", | |
641 | + use_default_enctypes ? " (with default enctypes)" : "", | |
642 | + code); | |
643 | + } | |
644 | +} | |
71f23813 JR |
645 | diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h |
646 | index da04530..2af1a25 100644 | |
647 | --- a/utils/gssd/krb5_util.h | |
648 | +++ b/utils/gssd/krb5_util.h | |
97cc26d8 JB |
649 | @@ -22,6 +22,8 @@ int gssd_refresh_krb5_machine_creds(voi |
650 | void gssd_free_krb5_machine_cred_list(char **list); | |
651 | void gssd_setup_krb5_machine_gss_ccache(char *servername); | |
652 | void gssd_destroy_krb5_machine_creds(void); | |
653 | +void gssd_obtain_kernel_krb5_info(void); | |
654 | + | |
655 | ||
656 | #ifdef HAVE_SET_ALLOWABLE_ENCTYPES | |
657 | int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid); | |
71f23813 JR |
658 | diff --git a/utils/gssd/context.h b/utils/gssd/context.h |
659 | index 67ed3bb..68b0c11 100644 | |
660 | --- a/utils/gssd/context.h | |
661 | +++ b/utils/gssd/context.h | |
97cc26d8 JB |
662 | @@ -1,5 +1,5 @@ |
663 | /* | |
664 | - Copyright (c) 2004 The Regents of the University of Michigan. | |
665 | + Copyright (c) 2004-2006 The Regents of the University of Michigan. | |
666 | All rights reserved. | |
667 | ||
668 | Redistribution and use in source and binary forms, with or without | |
71f23813 | 669 | @@ -36,6 +36,10 @@ #include <rpc/rpc.h> |
97cc26d8 JB |
670 | /* Hopefully big enough to hold any serialized context */ |
671 | #define MAX_CTX_LEN 4096 | |
672 | ||
673 | +/* New context format flag values */ | |
674 | +#define KRB5_CTX_FLAG_INITIATOR 0x00000001 | |
675 | +#define KRB5_CTX_FLAG_CFX 0x00000002 | |
676 | +#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | |
677 | ||
678 | int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf, | |
679 | gss_OID mech); | |
71f23813 JR |
680 | diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c |
681 | index 3550762..c824dcd 100644 | |
682 | --- a/utils/gssd/context_lucid.c | |
683 | +++ b/utils/gssd/context_lucid.c | |
684 | @@ -40,6 +40,7 @@ #ifdef HAVE_LUCID_CONTEXT_SUPPORT | |
97cc26d8 JB |
685 | #include <stdio.h> |
686 | #include <syslog.h> | |
687 | #include <string.h> | |
688 | +#include <errno.h> | |
689 | #include "gss_util.h" | |
690 | #include "gss_oids.h" | |
691 | #include "err_util.h" | |
71f23813 | 692 | @@ -113,15 +114,13 @@ #ifdef HAVE_HEIMDAL |
97cc26d8 JB |
693 | * Note that the rfc1964 version only supports DES enctypes. |
694 | */ | |
695 | if (lctx->rfc1964_kd.ctx_key.type != 4) { | |
696 | - printerr(1, "prepare_krb5_rfc1964_buffer: " | |
697 | - "overriding heimdal keytype (%d => %d)\n", | |
698 | - lctx->rfc1964_kd.ctx_key.type, 4); | |
699 | + printerr(2, "%s: overriding heimdal keytype (%d => %d)\n", | |
700 | + __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4); | |
701 | lctx->rfc1964_kd.ctx_key.type = 4; | |
702 | } | |
703 | #endif | |
704 | - printerr(2, "prepare_krb5_rfc1964_buffer: serializing keys with " | |
705 | - "enctype %d and length %d\n", | |
706 | - lctx->rfc1964_kd.ctx_key.type, | |
707 | + printerr(2, "%s: serializing keys with enctype %d and length %d\n", | |
708 | + __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, | |
709 | lctx->rfc1964_kd.ctx_key.length); | |
710 | ||
711 | /* derive the encryption key and copy it into buffer */ | |
712 | @@ -152,15 +151,361 @@ out_err: | |
713 | return -1; | |
714 | } | |
715 | ||
716 | -static int | |
717 | -prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx, | |
718 | - gss_buffer_desc *buf) | |
719 | +/* XXX Hack alert! XXX Do NOT submit upstream! XXX */ | |
720 | +/* XXX Hack alert! XXX Do NOT submit upstream! XXX */ | |
721 | + | |
722 | +/* for 3DES */ | |
723 | +#define KG_USAGE_SEAL 22 | |
724 | +#define KG_USAGE_SIGN 23 | |
725 | +#define KG_USAGE_SEQ 24 | |
726 | + | |
727 | +/* for rfc???? */ | |
728 | +#define KG_USAGE_ACCEPTOR_SEAL 22 | |
729 | +#define KG_USAGE_ACCEPTOR_SIGN 23 | |
730 | +#define KG_USAGE_INITIATOR_SEAL 24 | |
731 | +#define KG_USAGE_INITIATOR_SIGN 25 | |
732 | + | |
733 | +/* Lifted from mit src/lib/gssapi/krb5/gssapiP_krb5.h */ | |
734 | +enum seal_alg { | |
735 | + SEAL_ALG_NONE = 0xffff, | |
736 | + SEAL_ALG_DES = 0x0000, | |
737 | + SEAL_ALG_1 = 0x0001, /* not published */ | |
738 | + SEAL_ALG_MICROSOFT_RC4 = 0x0010, /* microsoft w2k; */ | |
739 | + SEAL_ALG_DES3KD = 0x0002 | |
740 | +}; | |
741 | + | |
742 | +#define KEY_USAGE_SEED_ENCRYPTION 0xAA | |
743 | +#define KEY_USAGE_SEED_INTEGRITY 0x55 | |
744 | +#define KEY_USAGE_SEED_CHECKSUM 0x99 | |
745 | +#define K5CLENGTH 5 | |
746 | + | |
747 | +/* Flags for version 2 context flags */ | |
748 | +#define KRB5_CTX_FLAG_INITIATOR 0x00000001 | |
749 | +#define KRB5_CTX_FLAG_CFX 0x00000002 | |
750 | +#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | |
751 | + | |
752 | +/* XXX Hack alert! XXX Do NOT submit upstream! XXX */ | |
753 | +/* XXX Hack alert! XXX Do NOT submit upstream! XXX */ | |
754 | +/* | |
755 | + * We don't have "legal" access to these MIT-only | |
756 | + * structures located in libk5crypto | |
757 | + */ | |
758 | +extern void krb5int_enc_arcfour; | |
759 | +extern void krb5int_enc_des3; | |
760 | +extern void krb5int_enc_aes128; | |
761 | +extern void krb5int_enc_aes256; | |
762 | +extern int krb5_derive_key(); | |
763 | + | |
764 | +static void | |
765 | +key_lucid_to_krb5(const gss_krb5_lucid_key_t *lin, krb5_keyblock *kout) | |
766 | { | |
767 | - printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n"); | |
768 | - return -1; | |
769 | + memset(kout, '\0', sizeof(kout)); | |
770 | +#ifdef HAVE_KRB5 | |
771 | + kout->enctype = lin->type; | |
772 | + kout->length = lin->length; | |
773 | + kout->contents = lin->data; | |
774 | +#else | |
775 | + kout->keytype = lin->type; | |
776 | + kout->keyvalue.length = lin->length; | |
777 | + kout->keyvalue.data = lin->data; | |
778 | +#endif | |
71f23813 JR |
779 | +} |
780 | + | |
97cc26d8 JB |
781 | +static void |
782 | +key_krb5_to_lucid(const krb5_keyblock *kin, gss_krb5_lucid_key_t *lout) | |
783 | +{ | |
784 | + memset(lout, '\0', sizeof(lout)); | |
785 | +#ifdef HAVE_KRB5 | |
786 | + lout->type = kin->enctype; | |
787 | + lout->length = kin->length; | |
788 | + lout->data = kin->contents; | |
789 | +#else | |
790 | + lout->type = kin->keytype; | |
791 | + lout->length = kin->keyvalue.length; | |
792 | + memcpy(lout->data, kin->keyvalue.data, kin->keyvalue.length); | |
793 | +#endif | |
794 | +} | |
71f23813 | 795 | + |
97cc26d8 JB |
796 | +/* XXX Hack alert! XXX Do NOT submit upstream! XXX */ |
797 | +/* XXX Hack alert! XXX Do NOT submit upstream! XXX */ | |
798 | +/* XXX Hack alert! XXX Do NOT submit upstream! XXX */ | |
799 | +/* XXX Hack alert! XXX Do NOT submit upstream! XXX */ | |
800 | +/* | |
801 | + * Function to derive a new key from a given key and given constant data. | |
802 | + */ | |
803 | +static krb5_error_code | |
804 | +derive_key_lucid(const gss_krb5_lucid_key_t *in, gss_krb5_lucid_key_t *out, | |
805 | + int usage, char extra) | |
806 | +{ | |
807 | + krb5_error_code code; | |
808 | + unsigned char constant_data[K5CLENGTH]; | |
809 | + krb5_data datain; | |
810 | + int keylength; | |
811 | + void *enc; | |
812 | + krb5_keyblock kin, kout; /* must send krb5_keyblock, not lucid! */ | |
813 | +#ifdef HAVE_HEIMDAL | |
814 | + krb5_context kcontext; | |
815 | + krb5_keyblock *outkey; | |
816 | +#endif | |
817 | + | |
818 | + /* | |
819 | + * XXX Hack alert. We don't have "legal" access to these | |
820 | + * values and structures located in libk5crypto | |
821 | + */ | |
822 | + switch (in->type) { | |
823 | + case ENCTYPE_DES3_CBC_SHA1: | |
824 | +#ifdef HAVE_KRB5 | |
825 | + case ENCTYPE_DES3_CBC_RAW: | |
826 | +#endif | |
827 | + keylength = 24; | |
828 | +#ifdef HAVE_KRB5 | |
829 | + enc = &krb5int_enc_des3; | |
830 | +#endif | |
831 | + break; | |
832 | + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | |
833 | + keylength = 16; | |
834 | +#ifdef HAVE_KRB5 | |
835 | + enc = &krb5int_enc_aes128; | |
836 | +#endif | |
837 | + break; | |
838 | + case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | |
839 | + keylength = 32; | |
840 | +#ifdef HAVE_KRB5 | |
841 | + enc = &krb5int_enc_aes256; | |
842 | +#endif | |
843 | + break; | |
844 | + default: | |
845 | + code = KRB5_BAD_ENCTYPE; | |
846 | + goto out; | |
847 | + } | |
848 | + | |
849 | + /* allocate memory for output key */ | |
850 | + if ((out->data = malloc(keylength)) == NULL) { | |
851 | + code = ENOMEM; | |
852 | + goto out; | |
853 | + } | |
854 | + out->length = keylength; | |
855 | + out->type = in->type; | |
856 | + | |
857 | + /* Convert to correct format for call to krb5_derive_key */ | |
858 | + key_lucid_to_krb5(in, &kin); | |
859 | + key_lucid_to_krb5(out, &kout); | |
860 | + | |
861 | + datain.data = (char *) constant_data; | |
862 | + datain.length = K5CLENGTH; | |
863 | + | |
864 | + ((char *)(datain.data))[0] = (usage>>24)&0xff; | |
865 | + ((char *)(datain.data))[1] = (usage>>16)&0xff; | |
866 | + ((char *)(datain.data))[2] = (usage>>8)&0xff; | |
867 | + ((char *)(datain.data))[3] = usage&0xff; | |
868 | + | |
869 | + ((char *)(datain.data))[4] = (char) extra; | |
870 | + | |
871 | +#ifdef HAVE_KRB5 | |
872 | + code = krb5_derive_key(enc, &kin, &kout, &datain); | |
873 | +#else | |
874 | + if ((code = krb5_init_context(&kcontext))) { | |
875 | + } | |
876 | + code = krb5_derive_key(kcontext, &kin, in->type, constant_data, K5CLENGTH, &outkey); | |
877 | +#endif | |
878 | + if (code) { | |
879 | + free(out->data); | |
880 | + out->data = NULL; | |
881 | + goto out; | |
882 | + } | |
883 | +#ifdef HAVE_KRB5 | |
884 | + key_krb5_to_lucid(&kout, out); | |
885 | +#else | |
886 | + key_krb5_to_lucid(outkey, out); | |
887 | + krb5_free_keyblock(kcontext, outkey); | |
888 | + krb5_free_context(kcontext); | |
889 | +#endif | |
890 | + | |
891 | + out: | |
892 | + if (code) | |
893 | + printerr(0, "ERROR: %s: returning error %d (%s)\n", | |
894 | + __FUNCTION__, code, error_message(code)); | |
895 | + return (code); | |
71f23813 JR |
896 | } |
897 | ||
898 | ||
97cc26d8 JB |
899 | +/* |
900 | + * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx), | |
901 | + * to send to the kernel for newer encryption types -- or for DES3. | |
902 | + * | |
903 | + * The new format is: | |
904 | + * | |
905 | + * u32 initiate; ( whether we are the initiator or not ) | |
906 | + * s32 endtime; | |
907 | + * u32 flags; | |
908 | + * #define KRB5_CTX_FLAG_INITIATOR 0x00000001 | |
909 | + * #define KRB5_CTX_FLAG_CFX 0x00000002 | |
910 | + * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | |
911 | + * u64 seq_send; | |
912 | + * u32 enctype; ( encrption type of keys ) | |
913 | + * u32 size_of_each_key; ( size of each key in bytes ) | |
914 | + * u32 number_of_keys; ( N -- should always be 3 for now ) | |
915 | + * keydata-1; ( Ke ) | |
916 | + * keydata-2; ( Ki ) | |
917 | + * keydata-3; ( Kc ) | |
918 | + * | |
919 | + */ | |
920 | +static int | |
921 | +prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, | |
922 | + gss_buffer_desc *buf) | |
923 | +{ | |
924 | + char *p, *end; | |
925 | + uint32_t v2_flags = 0; | |
926 | + gss_krb5_lucid_key_t enc_key; | |
927 | + gss_krb5_lucid_key_t derived_key; | |
928 | + gss_buffer_desc fakeoid; | |
929 | + uint32_t enctype; | |
930 | + uint32_t keysize; | |
931 | + uint32_t numkeys; | |
932 | + | |
933 | + memset(&enc_key, 0, sizeof(enc_key)); | |
934 | + memset(&fakeoid, 0, sizeof(fakeoid)); | |
935 | + | |
936 | + if (!(buf->value = calloc(1, MAX_CTX_LEN))) | |
937 | + goto out_err; | |
938 | + p = buf->value; | |
939 | + end = buf->value + MAX_CTX_LEN; | |
940 | + | |
941 | + /* Version 2 */ | |
942 | + if (WRITE_BYTES(&p, end, lctx->initiate)) goto out_err; | |
943 | + if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err; | |
944 | + | |
945 | + if (lctx->initiate) | |
946 | + v2_flags |= KRB5_CTX_FLAG_INITIATOR; | |
947 | + if (lctx->protocol != 0) | |
948 | + v2_flags |= KRB5_CTX_FLAG_CFX; | |
949 | + if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1) | |
950 | + v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY; | |
951 | + | |
952 | + if (WRITE_BYTES(&p, end, v2_flags)) goto out_err; | |
953 | + | |
954 | + if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err; | |
955 | + | |
956 | + /* Protocol 0 here implies DES3 or RC4 */ | |
957 | + printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); | |
958 | + if (lctx->protocol == 0) { | |
959 | + enctype = lctx->rfc1964_kd.ctx_key.type; | |
960 | +#ifdef HAVE_HEIMDAL | |
961 | + /* | |
962 | + * The kernel gss code expects ENCTYPE_DES3_CBC_RAW (6) for | |
963 | + * 3des keys, but Heimdal key has ENCTYPE_DES3_CBC_SHA1 (16). | |
964 | + * Force the Heimdal enctype to 6. | |
965 | + */ | |
966 | + if (enctype == ENCTYPE_DES3_CBC_SHA1) { | |
967 | + printerr(2, "%s: overriding heimdal keytype (%d => %d)\n", | |
968 | + __FUNCTION__, enctype, 6); | |
969 | + | |
970 | + enctype = 6; | |
971 | + } | |
972 | +#endif | |
973 | + keysize = lctx->rfc1964_kd.ctx_key.length; | |
974 | + numkeys = 3; /* XXX is always gonna be three? */ | |
975 | + } else { | |
976 | + if (lctx->cfx_kd.have_acceptor_subkey) { | |
977 | + enctype = lctx->cfx_kd.acceptor_subkey.type; | |
978 | + keysize = lctx->cfx_kd.acceptor_subkey.length; | |
979 | + } else { | |
980 | + enctype = lctx->cfx_kd.ctx_key.type; | |
981 | + keysize = lctx->cfx_kd.ctx_key.length; | |
982 | + } | |
983 | + numkeys = 3; | |
984 | + } | |
985 | + printerr(2, "%s: serializing %d keys with enctype %d and size %d\n", | |
986 | + __FUNCTION__, numkeys, enctype, keysize); | |
987 | + if (WRITE_BYTES(&p, end, enctype)) goto out_err; | |
988 | + if (WRITE_BYTES(&p, end, keysize)) goto out_err; | |
989 | + if (WRITE_BYTES(&p, end, numkeys)) goto out_err; | |
990 | + | |
991 | + if (lctx->protocol == 0) { | |
992 | + /* derive and send down: Ke, Ki, and Kc */ | |
993 | + /* Ke */ | |
994 | + if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data, | |
995 | + lctx->rfc1964_kd.ctx_key.length)) | |
996 | + goto out_err; | |
997 | + | |
998 | + /* Ki */ | |
999 | + if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data, | |
1000 | + lctx->rfc1964_kd.ctx_key.length)) | |
1001 | + goto out_err; | |
1002 | + | |
1003 | + /* Kc */ | |
1004 | + if (derive_key_lucid(&lctx->rfc1964_kd.ctx_key, | |
1005 | + &derived_key, | |
1006 | + KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM)) | |
1007 | + goto out_err; | |
1008 | + if (write_bytes(&p, end, derived_key.data, | |
1009 | + derived_key.length)) | |
1010 | + goto out_err; | |
1011 | + free(derived_key.data); | |
1012 | + } else { | |
1013 | + gss_krb5_lucid_key_t *keyptr; | |
1014 | + uint32_t sign_usage, seal_usage; | |
1015 | + | |
1016 | + if (lctx->cfx_kd.have_acceptor_subkey) | |
1017 | + keyptr = &lctx->cfx_kd.acceptor_subkey; | |
1018 | + else | |
1019 | + keyptr = &lctx->cfx_kd.ctx_key; | |
1020 | + | |
1021 | + if (lctx->initiate == 1) { | |
1022 | + sign_usage = KG_USAGE_INITIATOR_SIGN; | |
1023 | + seal_usage = KG_USAGE_INITIATOR_SEAL; | |
1024 | + } else { | |
1025 | + sign_usage = KG_USAGE_ACCEPTOR_SIGN; | |
1026 | + seal_usage = KG_USAGE_ACCEPTOR_SEAL; | |
1027 | + } | |
1028 | + | |
1029 | + /* derive and send down: Ke, Ki, and Kc */ | |
1030 | + | |
1031 | + /* Ke */ | |
1032 | + if (derive_key_lucid(keyptr, &derived_key, | |
1033 | + seal_usage, KEY_USAGE_SEED_ENCRYPTION)) | |
1034 | + goto out_err; | |
1035 | + if (write_bytes(&p, end, derived_key.data, | |
1036 | + derived_key.length)) | |
1037 | + goto out_err; | |
1038 | + free(derived_key.data); | |
1039 | + | |
1040 | + /* Ki */ | |
1041 | + if (derive_key_lucid(keyptr, &derived_key, | |
1042 | + seal_usage, KEY_USAGE_SEED_INTEGRITY)) | |
1043 | + goto out_err; | |
1044 | + if (write_bytes(&p, end, derived_key.data, | |
1045 | + derived_key.length)) | |
1046 | + goto out_err; | |
1047 | + free(derived_key.data); | |
1048 | + | |
1049 | + /* Kc */ | |
1050 | + if (derive_key_lucid(keyptr, &derived_key, | |
1051 | + sign_usage, KEY_USAGE_SEED_CHECKSUM)) | |
1052 | + goto out_err; | |
1053 | + if (write_bytes(&p, end, derived_key.data, | |
1054 | + derived_key.length)) | |
1055 | + goto out_err; | |
1056 | + free(derived_key.data); | |
1057 | + } | |
1058 | + | |
1059 | + buf->length = p - (char *)buf->value; | |
1060 | + return 0; | |
1061 | + | |
1062 | +out_err: | |
1063 | + printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n", | |
1064 | + __FUNCTION__); | |
1065 | + if (buf->value) { | |
1066 | + free(buf->value); | |
1067 | + buf->value = NULL; | |
1068 | + } | |
1069 | + buf->length = 0; | |
1070 | + if (enc_key.data) { | |
1071 | + free(enc_key.data); | |
1072 | + enc_key.data = NULL; | |
1073 | + } | |
1074 | + return -1; | |
1075 | +} | |
1076 | int | |
1077 | serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) | |
1078 | { | |
1079 | @@ -170,7 +515,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss | |
1080 | gss_krb5_lucid_context_v1_t *lctx = 0; | |
1081 | int retcode = 0; | |
1082 | ||
1083 | - printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n"); | |
1084 | + printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__); | |
1085 | maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx, | |
1086 | 1, &return_ctx); | |
1087 | if (maj_stat != GSS_S_COMPLETE) { | |
1088 | @@ -192,11 +537,20 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss | |
1089 | break; | |
1090 | } | |
1091 | ||
1092 | - /* Now lctx points to a lucid context that we can send down to kernel */ | |
1093 | - if (lctx->protocol == 0) | |
1094 | + /* | |
1095 | + * Now lctx points to a lucid context that we can send down to kernel | |
1096 | + * | |
1097 | + * Note: we send down different information to the kernel depending | |
1098 | + * on the protocol version and the enctyption type. | |
1099 | + * For protocol version 0 with all enctypes besides DES3, we use | |
1100 | + * the original format. For protocol version != 0 or DES3, we | |
1101 | + * send down the new style information. | |
1102 | + */ | |
1103 | + | |
1104 | + if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4) | |
1105 | retcode = prepare_krb5_rfc1964_buffer(lctx, buf); | |
1106 | else | |
1107 | - retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf); | |
1108 | + retcode = prepare_krb5_rfc4121_buffer(lctx, buf); | |
1109 | ||
1110 | maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx); | |
1111 | if (maj_stat != GSS_S_COMPLETE) { | |
1112 | @@ -206,8 +560,8 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss | |
1113 | } | |
1114 | ||
1115 | if (retcode) { | |
1116 | - printerr(1, "serialize_krb5_ctx: prepare_krb5_*_buffer " | |
1117 | - "failed (retcode = %d)\n", retcode); | |
1118 | + printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n", | |
1119 | + __FUNCTION__, retcode); | |
1120 | goto out_err; | |
1121 | } | |
1122 | ||
1123 | @@ -217,4 +571,7 @@ out_err: | |
1124 | printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); | |
1125 | return -1; | |
1126 | } | |
1127 | + | |
1128 | + | |
1129 | + | |
1130 | #endif /* HAVE_LUCID_CONTEXT_SUPPORT */ | |
71f23813 JR |
1131 | diff --git a/utils/gssd/context_mit.c b/utils/gssd/context_mit.c |
1132 | index 94b2266..cd6ab0f 100644 | |
1133 | --- a/utils/gssd/context_mit.c | |
1134 | +++ b/utils/gssd/context_mit.c | |
97cc26d8 JB |
1135 | @@ -1,5 +1,5 @@ |
1136 | /* | |
1137 | - Copyright (c) 2004 The Regents of the University of Michigan. | |
1138 | + Copyright (c) 2004-2006 The Regents of the University of Michigan. | |
1139 | All rights reserved. | |
1140 | ||
1141 | Redistribution and use in source and binary forms, with or without | |
71f23813 | 1142 | @@ -36,6 +36,7 @@ #ifdef HAVE_KRB5 |
97cc26d8 JB |
1143 | #include <stdio.h> |
1144 | #include <syslog.h> | |
1145 | #include <string.h> | |
1146 | +#include <errno.h> | |
a32f8019 | 1147 | #include <gssapi/gssapi.h> |
97cc26d8 JB |
1148 | #include <rpc/rpc.h> |
1149 | #include <rpc/auth_gss.h> | |
71f23813 | 1150 | @@ -50,8 +51,7 @@ #if (KRB5_VERSION > 131) |
97cc26d8 JB |
1151 | /* XXX argggg, there's gotta be a better way than just duplicating this |
1152 | * whole struct. Unfortunately, this is in a "private" header file, | |
1153 | * so this is our best choice at this point :-/ | |
1154 | - * | |
1155 | - * XXX Does this match the Heimdal definition? */ | |
1156 | + */ | |
1157 | ||
1158 | typedef struct _krb5_gss_ctx_id_rec { | |
1159 | unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */ | |
1160 | @@ -139,6 +139,124 @@ write_keyblock(char **p, char *end, stru | |
1161 | } | |
1162 | ||
1163 | /* | |
1164 | + * XXX Hack alert! XXX Do NOT submit upstream! | |
1165 | + * XXX Hack alert! XXX Do NOT submit upstream! | |
1166 | + * | |
1167 | + * We shouldn't be using these definitions | |
1168 | + * | |
1169 | + * XXX Hack alert! XXX Do NOT submit upstream! | |
1170 | + * XXX Hack alert! XXX Do NOT submit upstream! | |
1171 | + */ | |
1172 | +/* for 3DES */ | |
1173 | +#define KG_USAGE_SEAL 22 | |
1174 | +#define KG_USAGE_SIGN 23 | |
1175 | +#define KG_USAGE_SEQ 24 | |
1176 | + | |
1177 | +/* for rfc???? */ | |
1178 | +#define KG_USAGE_ACCEPTOR_SEAL 22 | |
1179 | +#define KG_USAGE_ACCEPTOR_SIGN 23 | |
1180 | +#define KG_USAGE_INITIATOR_SEAL 24 | |
1181 | +#define KG_USAGE_INITIATOR_SIGN 25 | |
1182 | + | |
1183 | +/* Lifted from mit src/lib/gssapi/krb5/gssapiP_krb5.h */ | |
1184 | +enum seal_alg { | |
1185 | + SEAL_ALG_NONE = 0xffff, | |
1186 | + SEAL_ALG_DES = 0x0000, | |
1187 | + SEAL_ALG_1 = 0x0001, /* not published */ | |
1188 | + SEAL_ALG_MICROSOFT_RC4 = 0x0010, /* microsoft w2k; */ | |
1189 | + SEAL_ALG_DES3KD = 0x0002 | |
1190 | +}; | |
1191 | + | |
1192 | +#define KEY_USAGE_SEED_ENCRYPTION 0xAA | |
1193 | +#define KEY_USAGE_SEED_INTEGRITY 0x55 | |
1194 | +#define KEY_USAGE_SEED_CHECKSUM 0x99 | |
1195 | +#define K5CLENGTH 5 | |
1196 | + | |
1197 | +extern void krb5_enc_des3; | |
1198 | +extern void krb5int_enc_des3; | |
1199 | +extern void krb5int_enc_arcfour; | |
1200 | +extern void krb5int_enc_aes128; | |
1201 | +extern void krb5int_enc_aes256; | |
1202 | +extern int krb5_derive_key(); | |
1203 | + | |
1204 | +/* | |
1205 | + * XXX Hack alert! XXX Do NOT submit upstream! | |
1206 | + * XXX Hack alert! XXX Do NOT submit upstream! | |
1207 | + * | |
1208 | + * We should be passing down a single key to the kernel | |
1209 | + * and it should be deriving the other keys. We cannot | |
1210 | + * depend on any of this stuff being accessible in the | |
1211 | + * future. | |
1212 | + * | |
1213 | + * XXX Hack alert! XXX Do NOT submit upstream! | |
1214 | + * XXX Hack alert! XXX Do NOT submit upstream! | |
1215 | + */ | |
1216 | +/* | |
1217 | + * Function to derive a new key from a given key and given constant data. | |
1218 | + */ | |
1219 | +static krb5_error_code | |
1220 | +derive_key(const krb5_keyblock *in, krb5_keyblock *out, int usage, char extra) | |
1221 | +{ | |
1222 | + krb5_error_code code; | |
1223 | + unsigned char constant_data[K5CLENGTH]; | |
1224 | + krb5_data datain; | |
1225 | + int keylength; | |
1226 | + void *enc; | |
1227 | + | |
1228 | + switch (in->enctype) { | |
1229 | +#ifdef ENCTYPE_DES3_CBC_RAW | |
1230 | + case ENCTYPE_DES3_CBC_RAW: | |
1231 | + keylength = 24; | |
1232 | +/* Extra hack, the structure was renamed as rc4 was added... */ | |
1233 | +#if defined(ENCTYPE_ARCFOUR_HMAC) | |
1234 | + enc = &krb5int_enc_des3; | |
1235 | +#else | |
1236 | + enc = &krb5_enc_des3; | |
1237 | +#endif | |
1238 | + break; | |
1239 | +#endif | |
1240 | +#ifdef ENCTYPE_ARCFOUR_HMAC | |
1241 | + case ENCTYPE_ARCFOUR_HMAC: | |
1242 | + keylength = 16; | |
1243 | + enc = &krb5int_enc_arcfour; | |
1244 | + break; | |
1245 | +#endif | |
1246 | + default: | |
1247 | + code = KRB5_BAD_ENCTYPE; | |
1248 | + goto out; | |
1249 | + } | |
1250 | + | |
1251 | + /* allocate memory for output key */ | |
1252 | + if ((out->contents = malloc(keylength)) == NULL) { | |
1253 | + code = ENOMEM; | |
1254 | + goto out; | |
1255 | + } | |
1256 | + out->length = keylength; | |
1257 | + out->enctype = in->enctype; | |
1258 | + | |
1259 | + datain.data = (char *) constant_data; | |
1260 | + datain.length = K5CLENGTH; | |
1261 | + | |
1262 | + datain.data[0] = (usage>>24)&0xff; | |
1263 | + datain.data[1] = (usage>>16)&0xff; | |
1264 | + datain.data[2] = (usage>>8)&0xff; | |
1265 | + datain.data[3] = usage&0xff; | |
1266 | + | |
1267 | + datain.data[4] = (char) extra; | |
1268 | + | |
1269 | + if ((code = krb5_derive_key(enc, in, out, &datain))) { | |
1270 | + free(out->contents); | |
1271 | + out->contents = NULL; | |
1272 | + } | |
1273 | + | |
1274 | + out: | |
1275 | + if (code) | |
1276 | + printerr(0, "ERROR: derive_key returning error %d (%s)\n", | |
1277 | + code, error_message(code)); | |
1278 | + return (code); | |
1279 | +} | |
1280 | + | |
1281 | +/* | |
1282 | * We really shouldn't know about glue-layer context structure, but | |
1283 | * we need to get at the real krb5 context pointer. This should be | |
1284 | * removed as soon as we say there is no support for MIT Kerberos | |
1285 | @@ -154,48 +272,124 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss | |
1286 | { | |
1287 | krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)ctx)->internal_ctx_id; | |
1288 | char *p, *end; | |
1289 | - static int constant_one = 1; | |
1290 | static int constant_zero = 0; | |
1291 | + static int constant_one = 1; | |
1292 | + static int constant_two = 2; | |
1293 | uint32_t word_seq_send; | |
1294 | + u_int64_t seq_send_64bit; | |
1295 | + uint32_t v2_flags = 0; | |
1296 | + krb5_keyblock derived_key; | |
1297 | + uint32_t numkeys; | |
1298 | ||
1299 | if (!(buf->value = calloc(1, MAX_CTX_LEN))) | |
1300 | goto out_err; | |
1301 | p = buf->value; | |
1302 | end = buf->value + MAX_CTX_LEN; | |
1303 | ||
1304 | - if (kctx->initiate) { | |
1305 | - if (WRITE_BYTES(&p, end, constant_one)) goto out_err; | |
1306 | - } | |
1307 | - else { | |
1308 | - if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; | |
1309 | - } | |
1310 | - if (kctx->seed_init) { | |
1311 | - if (WRITE_BYTES(&p, end, constant_one)) goto out_err; | |
1312 | - } | |
1313 | - else { | |
1314 | - if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; | |
1315 | - } | |
1316 | - if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed))) | |
71f23813 JR |
1317 | - goto out_err; |
1318 | - if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err; | |
1319 | - if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err; | |
1320 | - if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; | |
1321 | - word_seq_send = kctx->seq_send; | |
1322 | - if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err; | |
1323 | - if (write_oid(&p, end, kctx->mech_used)) goto out_err; | |
97cc26d8 JB |
1324 | + switch (kctx->sealalg) { |
1325 | + case SEAL_ALG_DES: | |
1326 | + /* Old format of context to the kernel */ | |
1327 | + if (kctx->initiate) { | |
1328 | + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; | |
1329 | + } | |
1330 | + else { | |
1331 | + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; | |
1332 | + } | |
1333 | + if (kctx->seed_init) { | |
1334 | + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; | |
1335 | + } | |
1336 | + else { | |
1337 | + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; | |
1338 | + } | |
1339 | + if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed))) | |
1340 | + goto out_err; | |
1341 | + if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err; | |
1342 | + if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err; | |
1343 | + if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; | |
1344 | + word_seq_send = kctx->seq_send; | |
1345 | + if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err; | |
1346 | + if (write_oid(&p, end, kctx->mech_used)) goto out_err; | |
1347 | + | |
1348 | + printerr(2, "serialize_krb5_ctx: serializing keys with " | |
1349 | + "enctype %d and length %d\n", | |
1350 | + kctx->enc->enctype, kctx->enc->length); | |
1351 | + | |
1352 | + if (write_keyblock(&p, end, kctx->enc)) goto out_err; | |
1353 | + if (write_keyblock(&p, end, kctx->seq)) goto out_err; | |
1354 | + break; | |
1355 | + case SEAL_ALG_MICROSOFT_RC4: | |
1356 | + case SEAL_ALG_DES3KD: | |
1357 | + /* New format of context to the kernel */ | |
1358 | + /* s32 endtime; | |
1359 | + * u32 flags; | |
1360 | + * #define KRB5_CTX_FLAG_INITIATOR 0x00000001 | |
1361 | + * #define KRB5_CTX_FLAG_CFX 0x00000002 | |
1362 | + * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | |
1363 | + * u64 seq_send; | |
1364 | + * u32 enctype; | |
1365 | + * u32 size_of_each_key; ( size in bytes ) | |
1366 | + * u32 number_of_keys; ( N (assumed to be 3 for now) ) | |
1367 | + * keydata-1; ( Ke (Kenc for DES3) ) | |
1368 | + * keydata-2; ( Ki (Kseq for DES3) ) | |
1369 | + * keydata-3; ( Kc (derived checksum key) ) | |
1370 | + */ | |
1371 | + if (kctx->initiate) { | |
1372 | + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; | |
1373 | + } | |
1374 | + else { | |
1375 | + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; | |
1376 | + } | |
1377 | + if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; | |
1378 | + | |
1379 | + /* Only applicable flag for this is initiator */ | |
1380 | + if (kctx->initiate) v2_flags |= KRB5_CTX_FLAG_INITIATOR; | |
1381 | + if (WRITE_BYTES(&p, end, v2_flags)) goto out_err; | |
1382 | + | |
1383 | + seq_send_64bit = kctx->seq_send; | |
1384 | + if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err; | |
71f23813 JR |
1385 | |
1386 | - printerr(2, "serialize_krb5_ctx: serializing keys with " | |
1387 | - "enctype %d and length %d\n", | |
1388 | - kctx->enc->enctype, kctx->enc->length); | |
97cc26d8 JB |
1389 | + if (WRITE_BYTES(&p, end, kctx->enc->enctype)) goto out_err; |
1390 | + if (WRITE_BYTES(&p, end, kctx->enc->length)) goto out_err; | |
1391 | + numkeys = 3; | |
1392 | + if (WRITE_BYTES(&p, end, numkeys)) goto out_err; | |
1393 | + printerr(2, "serialize_krb5_ctx: serializing %d keys with " | |
1394 | + "enctype %d and size %d\n", | |
1395 | + numkeys, kctx->enc->enctype, kctx->enc->length); | |
71f23813 JR |
1396 | |
1397 | - if (write_keyblock(&p, end, kctx->enc)) goto out_err; | |
1398 | - if (write_keyblock(&p, end, kctx->seq)) goto out_err; | |
97cc26d8 JB |
1399 | + /* Ke */ |
1400 | + if (write_bytes(&p, end, kctx->enc->contents, | |
1401 | + kctx->enc->length)) | |
1402 | + goto out_err; | |
1403 | + | |
1404 | + /* Ki */ | |
1405 | + if (write_bytes(&p, end, kctx->enc->contents, | |
1406 | + kctx->enc->length)) | |
1407 | + goto out_err; | |
1408 | + | |
1409 | + /* Kc */ | |
1410 | + if (derive_key(kctx->seq, &derived_key, | |
1411 | + KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM)) | |
1412 | + goto out_err; | |
1413 | + if (write_bytes(&p, end, derived_key.contents, | |
1414 | + derived_key.length)) | |
1415 | + goto out_err; | |
1416 | + free(derived_key.contents); | |
1417 | + break; | |
1418 | + default: | |
1419 | + printerr(0, "ERROR: serialize_krb5_ctx: unsupported seal " | |
1420 | + "algorithm %d\n", kctx->sealalg); | |
71f23813 | 1421 | + goto out_err; |
97cc26d8 JB |
1422 | + } |
1423 | ||
1424 | buf->length = p - (char *)buf->value; | |
1425 | return 0; | |
1426 | + | |
1427 | out_err: | |
1428 | printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); | |
1429 | - if (buf->value) free(buf->value); | |
1430 | + if (buf->value) { | |
1431 | + free(buf->value); | |
1432 | + } | |
1433 | + buf->value = NULL; | |
1434 | buf->length = 0; | |
1435 | return -1; | |
1436 | } |