Skip to content

Commit f93ca02

Browse files
committed
Add ability to pass keyfile via cred store
This works both for ISC and ASC, so a user can pass their own keyfile with a single entry or a server can be passed a keyfile with all users' entries. Signed-off-by: Simo Sorce <[email protected]>
1 parent 336473a commit f93ca02

File tree

6 files changed

+141
-62
lines changed

6 files changed

+141
-62
lines changed

src/gss_creds.c

Lines changed: 61 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,23 @@ static int hex_to_key(const char *hex, struct ntlm_key *key)
3535
return 0;
3636
}
3737

38-
static int get_user_file_creds(struct gssntlm_name *name,
38+
static char *get_user_file_envvar(void)
39+
{
40+
const char *envvar;
41+
42+
/* use the same var used by Heimdal */
43+
envvar = getenv("NTLM_USER_FILE");
44+
if (envvar == NULL) return NULL;
45+
46+
return strdup(envvar);
47+
}
48+
49+
static int get_user_file_creds(const char *filename,
50+
struct gssntlm_name *name,
3951
struct gssntlm_cred *cred)
4052
{
4153
struct gssntlm_ctx *ctx;
4254
int lm_compat_lvl = -1;
43-
const char *envvar;
4455
char line[1024];
4556
char *field1, *field2, *field3, *field4;
4657
char *dom, *usr, *pwd, *lm, *nt;
@@ -55,10 +66,6 @@ static int get_user_file_creds(struct gssntlm_name *name,
5566
lm_compat_lvl = gssntlm_get_lm_compatibility_level();
5667
if (!gssntlm_required_security(lm_compat_lvl, ctx)) return ERR_BADLMLVL;
5768

58-
/* use the same var used by Heimdal */
59-
envvar = getenv("NTLM_USER_FILE");
60-
if (envvar == NULL) return ENOENT;
61-
6269
/* Use the same file format used by Heimdal in hope to achieve
6370
* some compatibility between implementations:
6471
* Each line is one entry like the following:
@@ -80,7 +87,7 @@ static int get_user_file_creds(struct gssntlm_name *name,
8087
* recommended.
8188
*/
8289

83-
f = fopen(envvar, "r");
90+
f = fopen(filename, "r");
8491
if (!f) return errno;
8592

8693
while(fgets(line, 1024, f)) {
@@ -228,31 +235,33 @@ static int get_creds_from_store(struct gssntlm_name *name,
228235
uint32_t i;
229236
int ret;
230237

231-
cred->type = GSSNTLM_CRED_NONE;
232-
233-
if (name) {
234-
switch (name->type) {
235-
case GSSNTLM_NAME_NULL:
236-
cred->type = GSSNTLM_CRED_NONE;
237-
break;
238-
case GSSNTLM_NAME_ANON:
239-
cred->type = GSSNTLM_CRED_ANON;
240-
break;
241-
case GSSNTLM_NAME_USER:
242-
cred->type = GSSNTLM_CRED_USER;
243-
ret = gssntlm_copy_name(name, &cred->cred.user.user);
244-
break;
245-
case GSSNTLM_NAME_SERVER:
246-
cred->type = GSSNTLM_CRED_SERVER;
247-
ret = gssntlm_copy_name(name, &cred->cred.server.name);
248-
break;
249-
default:
250-
return EINVAL;
238+
/* special case to let server creds carry a keyfile */
239+
if (name->type == GSSNTLM_NAME_SERVER) {
240+
const char *keyfile = NULL;
241+
cred->type = GSSNTLM_CRED_SERVER;
242+
ret = gssntlm_copy_name(name, &cred->cred.server.name);
243+
if (ret) return ret;
244+
for (i = 0; i < cred_store->count; i++) {
245+
if (strcmp(cred_store->elements[i].key,
246+
GSS_NTLMSSP_CS_KEYFILE) == 0) {
247+
keyfile = cred_store->elements[i].value;
248+
}
251249
}
250+
if (keyfile) {
251+
cred->cred.server.keyfile = strdup(keyfile);
252+
if (cred->cred.server.keyfile == NULL) {
253+
return errno;
254+
}
255+
}
256+
return 0;
252257
}
253258

254259
/* so far only user options can be defined in the cred_store */
255-
if (cred->type != GSSNTLM_CRED_USER) return ENOENT;
260+
if (name->type != GSSNTLM_NAME_USER) return ENOENT;
261+
262+
cred->type = GSSNTLM_CRED_USER;
263+
ret = gssntlm_copy_name(name, &cred->cred.user.user);
264+
if (ret) return ret;
256265

257266
for (i = 0; i < cred_store->count; i++) {
258267
if (strcmp(cred_store->elements[i].key, GSS_NTLMSSP_CS_DOMAIN) == 0) {
@@ -285,12 +294,13 @@ static int get_creds_from_store(struct gssntlm_name *name,
285294

286295
if (ret) return ret;
287296
}
297+
if (strcmp(cred_store->elements[i].key, GSS_NTLMSSP_CS_KEYFILE) == 0) {
298+
ret = get_user_file_creds(cred_store->elements[i].value,
299+
name, cred);
300+
if (ret) return ret;
301+
}
288302
}
289303

290-
/* TODO: should we call get_user_file_creds/get_server_creds if values are
291-
* not found ?
292-
*/
293-
294304
return 0;
295305
}
296306

@@ -363,6 +373,7 @@ void gssntlm_int_release_cred(struct gssntlm_cred *cred)
363373
break;
364374
case GSSNTLM_CRED_SERVER:
365375
gssntlm_int_release_name(&cred->cred.server.name);
376+
safefree(cred->cred.server.keyfile);
366377
break;
367378
case GSSNTLM_CRED_EXTERNAL:
368379
gssntlm_int_release_name(&cred->cred.external.user);
@@ -423,10 +434,19 @@ uint32_t gssntlm_acquire_cred_from(uint32_t *minor_status,
423434
if (cred_store != GSS_C_NO_CRED_STORE) {
424435
retmin = get_creds_from_store(name, cred, cred_store);
425436
} else {
426-
retmin = get_user_file_creds(name, cred);
437+
char *filename;
438+
439+
filename = get_user_file_envvar();
440+
if (!filename) {
441+
set_GSSERRS(ENOENT, GSS_S_CRED_UNAVAIL);
442+
goto done;
443+
}
444+
retmin = get_user_file_creds(filename, name, cred);
427445
if (retmin) {
428446
retmin = external_get_creds(name, cred);
429447
}
448+
449+
free(filename);
430450
}
431451
if (retmin) {
432452
set_GSSERR(retmin);
@@ -438,10 +458,14 @@ uint32_t gssntlm_acquire_cred_from(uint32_t *minor_status,
438458
goto done;
439459
}
440460

441-
retmin = get_server_creds(name, cred);
442-
if (retmin) {
443-
set_GSSERR(retmin);
444-
goto done;
461+
if (cred_store != GSS_C_NO_CRED_STORE) {
462+
retmin = get_creds_from_store(name, cred, cred_store);
463+
} else {
464+
retmin = get_server_creds(name, cred);
465+
if (retmin) {
466+
set_GSSERR(retmin);
467+
goto done;
468+
}
445469
}
446470
} else if (cred_usage == GSS_C_BOTH) {
447471
set_GSSERRS(ERR_NOTSUPPORTED, GSS_S_CRED_UNAVAIL);

src/gss_ntlmssp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ struct gssntlm_cred {
7979
} user;
8080
struct {
8181
struct gssntlm_name name;
82+
char *keyfile;
8283
} server;
8384
struct {
8485
struct gssntlm_name user;

src/gss_sec_ctx.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status,
525525
gss_cred_id_t *delegated_cred_handle)
526526
{
527527
struct gssntlm_ctx *ctx;
528-
struct gssntlm_cred *cred;
528+
struct gssntlm_cred *cred = NULL;
529529
int lm_compat_lvl = -1;
530530
struct ntlm_buffer challenge = { 0 };
531531
struct gssntlm_name *server_name = NULL;
@@ -844,6 +844,9 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status,
844844
char useratdom[1024];
845845
size_t ulen, dlen, uadlen;
846846
gss_buffer_desc usrname;
847+
gss_const_key_value_set_t cred_store = GSS_C_NO_CRED_STORE;
848+
gss_key_value_set_desc cs;
849+
gss_key_value_element_desc cs_el;
847850

848851
if (!dom_name) {
849852
dom_name = strdup("");
@@ -876,13 +879,22 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status,
876879
(gss_name_t *)&gss_usrname);
877880
if (retmaj) goto done;
878881

879-
retmaj = gssntlm_acquire_cred(&retmin,
880-
(gss_name_t)gss_usrname,
881-
GSS_C_INDEFINITE,
882-
GSS_C_NO_OID_SET,
883-
GSS_C_INITIATE,
884-
(gss_cred_id_t *)&usr_cred,
885-
NULL, NULL);
882+
if (cred && cred->cred.server.keyfile) {
883+
cs_el.key = GSS_NTLMSSP_CS_KEYFILE;
884+
cs_el.value = cred->cred.server.keyfile;
885+
cs.count = 1;
886+
cs.elements = &cs_el;
887+
cred_store = &cs;
888+
}
889+
890+
retmaj = gssntlm_acquire_cred_from(&retmin,
891+
(gss_name_t)gss_usrname,
892+
GSS_C_INDEFINITE,
893+
GSS_C_NO_OID_SET,
894+
GSS_C_INITIATE,
895+
cred_store,
896+
(gss_cred_id_t *)&usr_cred,
897+
NULL, NULL);
886898
if (retmaj) goto done;
887899
/* We can't handle winbind credentials yet */
888900
if (usr_cred->type != GSSNTLM_CRED_USER &&

src/gss_serialize.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ struct export_cred {
776776
struct export_name name; /* user or server name */
777777
struct relmem nt_hash; /* empty for dummy or server */
778778
struct relmem lm_hash; /* empty for dummy or server */
779+
struct relmem keyfile;
779780
uint8_t ext_cached;
780781

781782
uint8_t data[];
@@ -863,6 +864,20 @@ uint32_t gssntlm_export_cred(uint32_t *minor_status,
863864
set_GSSERR(ret);
864865
goto done;
865866
}
867+
868+
if (cred->cred.server.keyfile) {
869+
ret = export_data_buffer(&state,
870+
cred->cred.server.keyfile,
871+
strlen(cred->cred.server.keyfile),
872+
&ecred->keyfile);
873+
if (ret) {
874+
set_GSSERR(ret);
875+
goto done;
876+
}
877+
} else {
878+
ecred->keyfile.ptr = 0;
879+
ecred->keyfile.len = 0;
880+
}
866881
break;
867882
case GSSNTLM_CRED_EXTERNAL:
868883
ecred->type = EXP_CRED_EXTERNAL;
@@ -965,6 +980,12 @@ uint32_t gssntlm_import_cred(uint32_t *minor_status,
965980
retmaj = import_name(&retmin, &state, &ecred->name,
966981
&cred->cred.server.name);
967982
if (retmaj != GSS_S_COMPLETE) goto done;
983+
if (ecred->keyfile.len > 0) {
984+
retmaj = import_data_buffer(&retmin, &state,
985+
(uint8_t **)&cred->cred.server.keyfile,
986+
NULL, true, &ecred->keyfile, true);
987+
if (retmaj != GSS_S_COMPLETE) goto done;
988+
}
968989
break;
969990
case EXP_CRED_EXTERNAL:
970991
cred->type = GSSNTLM_CRED_EXTERNAL;

src/gssapi_ntlmssp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ extern "C" {
5656
#define GSS_NTLMSSP_CS_DOMAIN "ntlmssp_domain"
5757
#define GSS_NTLMSSP_CS_NTHASH "ntlmssp_nthash"
5858
#define GSS_NTLMSSP_CS_PASSWORD "ntlmssp_password"
59+
#define GSS_NTLMSSP_CS_KEYFILE "ntlmssp_keyfile"
5960

6061
#ifdef __cplusplus
6162
}

tests/ntlmssptest.c

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,7 +1448,7 @@ static void print_gss_error(const char *text, uint32_t maj, uint32_t min)
14481448
fflush(stderr);
14491449
}
14501450

1451-
int test_gssapi_1(bool user_env_file, bool use_cb, bool no_seal)
1451+
int test_gssapi_1(bool user_env_file, bool use_cb, bool no_seal, bool use_cs)
14521452
{
14531453
gss_ctx_id_t cli_ctx = GSS_C_NO_CONTEXT;
14541454
gss_ctx_id_t srv_ctx = GSS_C_NO_CONTEXT;
@@ -1475,14 +1475,27 @@ int test_gssapi_1(bool user_env_file, bool use_cb, bool no_seal)
14751475
gss_OID_desc sasl_ssf_oid = {
14761476
11, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f")
14771477
};
1478+
gss_key_value_element_desc cs_el;
1479+
gss_key_value_set_desc cs;
1480+
gss_const_key_value_set_t cred_store = GSS_C_NO_CRED_STORE;
14781481
uint32_t ssf, expect_ssf;
14791482
uint32_t req_flags;
14801483
int conf_state;
14811484
int ret;
14821485

1483-
setenv("NTLM_USER_FILE", TEST_USER_FILE, 0);
1486+
if (use_cs) {
1487+
/* always use the default test file and name in this mode for now */
1488+
cs_el.key = GSS_NTLMSSP_CS_KEYFILE;
1489+
cs_el.value = TEST_USER_FILE;
1490+
cs.count = 1;
1491+
cs.elements = &cs_el;
1492+
cred_store = &cs;
1493+
username = NULL;
1494+
} else {
1495+
setenv("NTLM_USER_FILE", TEST_USER_FILE, 0);
1496+
username = getenv("TEST_USER_NAME");
1497+
}
14841498

1485-
username = getenv("TEST_USER_NAME");
14861499
if (username == NULL) {
14871500
username = "TESTDOM\\testuser";
14881501
}
@@ -1497,10 +1510,11 @@ int test_gssapi_1(bool user_env_file, bool use_cb, bool no_seal)
14971510
return EINVAL;
14981511
}
14991512

1500-
if (user_env_file) {
1501-
retmaj = gssntlm_acquire_cred(&retmin, (gss_name_t)gss_username,
1502-
GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
1503-
GSS_C_INITIATE, &cli_cred, NULL, NULL);
1513+
if (user_env_file || use_cs) {
1514+
retmaj = gssntlm_acquire_cred_from(&retmin, (gss_name_t)gss_username,
1515+
GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
1516+
GSS_C_INITIATE, cred_store,
1517+
&cli_cred, NULL, NULL);
15041518
if (retmaj != GSS_S_COMPLETE) {
15051519
print_gss_error("gssntlm_acquire_cred(username) failed!",
15061520
retmaj, retmin);
@@ -1544,9 +1558,10 @@ int test_gssapi_1(bool user_env_file, bool use_cb, bool no_seal)
15441558
return EINVAL;
15451559
}
15461560

1547-
retmaj = gssntlm_acquire_cred(&retmin, (gss_name_t)gss_srvname,
1548-
GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
1549-
GSS_C_ACCEPT, &srv_cred, NULL, NULL);
1561+
retmaj = gssntlm_acquire_cred_from(&retmin, (gss_name_t)gss_srvname,
1562+
GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
1563+
GSS_C_ACCEPT, cred_store,
1564+
&srv_cred, NULL, NULL);
15501565
if (retmaj != GSS_S_COMPLETE) {
15511566
print_gss_error("gssntlm_acquire_cred(srvname) failed!",
15521567
retmaj, retmin);
@@ -2445,17 +2460,22 @@ int main(int argc, const char *argv[])
24452460
setenv("LM_COMPAT_LEVEL", "0", 1);
24462461

24472462
fprintf(stderr, "Test GSSAPI conversation (user env file)\n");
2448-
ret = test_gssapi_1(true, false, false);
2463+
ret = test_gssapi_1(true, false, false, false);
2464+
fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
2465+
if (ret) gret++;
2466+
2467+
fprintf(stderr, "Test GSSAPI conversation (cred store)\n");
2468+
ret = test_gssapi_1(true, false, false, true);
24492469
fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
24502470
if (ret) gret++;
24512471

24522472
fprintf(stderr, "Test GSSAPI conversation (no SEAL)\n");
2453-
ret = test_gssapi_1(true, false, true);
2473+
ret = test_gssapi_1(true, false, true, false);
24542474
fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
24552475
if (ret) gret++;
24562476

24572477
fprintf(stderr, "Test GSSAPI conversation (with password)\n");
2458-
ret = test_gssapi_1(false, false, false);
2478+
ret = test_gssapi_1(false, false, false, false);
24592479
fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
24602480
if (ret) gret++;
24612481

@@ -2468,22 +2488,22 @@ int main(int argc, const char *argv[])
24682488
setenv("LM_COMPAT_LEVEL", "5", 1);
24692489

24702490
fprintf(stderr, "Test GSSAPI conversation (user env file)\n");
2471-
ret = test_gssapi_1(true, false, false);
2491+
ret = test_gssapi_1(true, false, false, false);
24722492
fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
24732493
if (ret) gret++;
24742494

24752495
fprintf(stderr, "Test GSSAPI conversation (no SEAL)\n");
2476-
ret = test_gssapi_1(true, false, true);
2496+
ret = test_gssapi_1(true, false, true, false);
24772497
fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
24782498
if (ret) gret++;
24792499

24802500
fprintf(stderr, "Test GSSAPI conversation (with password)\n");
2481-
ret = test_gssapi_1(false, false, false);
2501+
ret = test_gssapi_1(false, false, false, false);
24822502
fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
24832503
if (ret) gret++;
24842504

24852505
fprintf(stderr, "Test GSSAPI conversation (with CB)\n");
2486-
ret = test_gssapi_1(false, true, false);
2506+
ret = test_gssapi_1(false, true, false, false);
24872507
fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
24882508
if (ret) gret++;
24892509

0 commit comments

Comments
 (0)