Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S266307AbUFPOkk (ORCPT ); Wed, 16 Jun 2004 10:40:40 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S266286AbUFPOkk (ORCPT ); Wed, 16 Jun 2004 10:40:40 -0400 Received: from mx1.redhat.com ([66.187.233.31]:26291 "EHLO mx1.redhat.com") by vger.kernel.org with ESMTP id S266318AbUFPOiM (ORCPT ); Wed, 16 Jun 2004 10:38:12 -0400 From: David Howells In-Reply-To: <20040615152912.C22989@build.pdx.osdl.net> References: <20040615152912.C22989@build.pdx.osdl.net> <1087282990.13680.13.camel@lade.trondhjem.org> <772741DF-BC19-11D8-888F-000393ACC76E@mac.com> <1087080664.4683.8.camel@lade.trondhjem.org> <1087084736.4683.17.camel@lade.trondhjem.org> <87smcxqqa2.fsf@asterisk.co.nz> <1087282990.13680.13.camel@lade.trondhjem.org> <8666.1087292194@redhat.com> To: Chris Wright Cc: Blair Strang , Kyle Moffett , Linus Torvalds , lkml Subject: Re: In-kernel Authentication Tokens (PAGs) User-Agent: EMH/1.14.1 SEMI/1.14.5 (Awara-Onsen) FLIM/1.14.5 (Demachiyanagi) APEL/10.6 Emacs/21.3 (i386-redhat-linux-gnu) MULE/5.0 (SAKAKI) MIME-Version: 1.0 (generated by SEMI 1.14.5 - "Awara-Onsen") Content-Type: multipart/mixed; boundary="Multipart_Wed_Jun_16_15:37:57_2004-1" Date: Wed, 16 Jun 2004 15:37:57 +0100 Message-ID: <10229.1087396677@redhat.com> Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 13898 Lines: 538 --Multipart_Wed_Jun_16_15:37:57_2004-1 Content-Type: text/plain; charset=US-ASCII > > I've a sample aklog program (key submission) should you be interested. > > I'd be intereseted. BTW, I just took a brief look and had a quick > question. Please see attached files. key_afs.c Rudimentary kAFS filesystem token handling afsutil.h } kernel.c } aklog program aklog.c } > > + if (bprm->e_uid != current->uid) > > + suid_keys(current); > > + exec_keys(current); > > + > > would the security module be expected update/revoke keys if the thing changes > security domains on exec? I don't know. Currently this patch replaces the old session keyring in favour of a new empty one upon SUID exec. I suspect that depends on the policy set by the administrator. If you've a better suggestion than what I've done, feel free to make it. > > task_lock(current); > > unsafe = unsafe_exec(current); > > security_bprm_apply_creds(bprm, unsafe); David --Multipart_Wed_Jun_16_15:37:57_2004-1 Content-Type: application/octet-stream Content-Disposition: attachment; filename="key_afs.c" Content-Transfer-Encoding: 7bit /* key_afs.c: AFS filesystem keys * * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include "cell.h" #include "internal.h" static int afs_key_init(struct key *key, const char *desc, size_t datalen, const char *data); static int afs_key_match(const struct key *key, const void *desc); static void afs_key_clear(struct key *key); static void afs_key_describe(const struct key *keyring, struct seq_file *m); struct afs_key_data { uint16_t session_key_size; uint16_t ticket_size; int32_t kvno; time_t expiry; uint8_t data[0]; }; /* AFS Kerberos ticket * - the description must be the name of the cell to which applicable * - the data is a struct afs_key_data */ struct key_type key_type_afs = { .name = "afs", .link = LIST_HEAD_INIT(key_type_afs.link), .init = afs_key_init, .match = afs_key_match, .clear = afs_key_clear, .describe = afs_key_describe, }; static int afs_key_init(struct key *key, const char *desc, size_t datalen, const char *data) { struct afs_key_data *keydata = (void *) data; size_t dlen; kenter("{%u},%s,%zu,{sk=%hu,tkt=%hu,v=%d,xp=%x}", key->serial, desc, datalen, keydata->session_key_size, keydata->ticket_size, keydata->kvno, (int) keydata->expiry); dlen = strlen(desc) + 1; key->description.data = kmalloc(dlen, GFP_KERNEL); if (!key->description.data) { kleave(" = -ENOMEM"); return -ENOMEM; } memcpy(key->description.data, desc, dlen); key->payload.data = kmalloc(datalen, GFP_KERNEL); if (!key->payload.data) { kleave(" = -ENOMEM"); return -ENOMEM; } key->datalen = datalen; memcpy(key->payload.data, data, datalen); kleave(" = 0"); return 0; } static int afs_key_match(const struct key *key, const void *desc) { if (!key->description.data) return 0; return strcmp(key->description.data, desc) == 0 ? 1 : 0; } static void afs_key_clear(struct key *key) { if (key->description.data) kfree(key->description.data); if (key->payload.data) kfree(key->payload.data); } static void afs_key_describe(const struct key *key, struct seq_file *m) { struct afs_key_data *keydata; if (!key->description.data) { seq_puts(m, "[anon]"); return; } keydata = key->payload.data; seq_printf(m, "%s => { s=%hu t=%hu v=%d x=%lx }", (char *) key->description.data, keydata->session_key_size, keydata->ticket_size, keydata->kvno, (int) keydata->expiry - CURRENT_TIME.tv_sec); } int __init afs_key_register(void) { return register_key_type(&key_type_afs); } void __exit afs_key_unregister(void) { unregister_key_type(&key_type_afs); } --Multipart_Wed_Jun_16_15:37:57_2004-1 Content-Type: application/octet-stream Content-Disposition: attachment; filename="afsutil.h" Content-Transfer-Encoding: 7bit /* afsutil.h: AFS client utility library * * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #ifndef _AFS_UTIL_H #define _AFS_UTIL_H #include #include extern int afsutil_authorise_krb5(const char *cell, const char *realm, time_t expiry, size_t session_key_size, const void *session_key, int ticket_kvno, size_t ticket_size, const void *ticket); #endif /* _AFS_UTIL_H */ --Multipart_Wed_Jun_16_15:37:57_2004-1 Content-Type: application/octet-stream Content-Disposition: attachment; filename="kernel.c" Content-Transfer-Encoding: 7bit /* kernel.c: routines for talking to the kernel * * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include /* Manage a process's keyrings */ #define PR_SPEC_THREAD_KEYRING 0 /* - specifier for thread-specific keyring */ #define PR_SPEC_PROCESS_KEYRING 1 /* - specifier for process-specific keyring */ #define PR_SPEC_SESSION_KEYRING 2 /* - specifier for session-specific keyring */ #define PR_SPEC_USER_KEYRING 3 /* - specifier for UID-specific keyring */ #define PR_SPEC_GROUP_KEYRING 4 /* - specifier for GID-specific keyring */ #define PR_GET_KEYRING_ID 15 /* ask for specified keyring's ID */ #define PR_CLEAR_KEYRING 16 /* clear contents of specified keyring */ #define PR_NEW_SESSION_KEYRING 17 /* start a new session keyring */ #define PR_ADD_NEW_KEY 18 /* add a key to specified keyring */ typedef int32_t key_serial_t; struct afs_key_data { uint16_t session_key_size; uint16_t ticket_size; int32_t kvno; time_t expiry; uint8_t data[0]; }; /*****************************************************************************/ /* * pass authorisation information to the kernel indicating that we have a valid * kerberos4 ticket */ int afsutil_authorise_krb5(const char *cell, const char *realm, time_t expiry, size_t session_key_size, const void *session_key, int ticket_kvno, size_t ticket_size, const void *ticket) { struct afs_key_data *keydata; uint16_t payload_size; void *buffer; int ret; payload_size = sizeof(struct afs_key_data) + session_key_size + ticket_size; buffer = alloca(sizeof(uint16_t) + payload_size); *(uint16_t *) buffer = payload_size; keydata = buffer + sizeof(uint16_t); keydata->session_key_size = session_key_size; keydata->ticket_size = ticket_size; keydata->kvno = ticket_kvno; keydata->expiry = expiry; memcpy(keydata->data, session_key, session_key_size); memcpy(keydata->data + session_key_size, ticket, ticket_size); if (prctl(PR_ADD_NEW_KEY, PR_SPEC_SESSION_KEYRING, "afs", cell, buffer) < 0) return -1; return 0; } /* end afsutil_authorise_krb5() */ --Multipart_Wed_Jun_16_15:37:57_2004-1 Content-Type: application/octet-stream Content-Disposition: attachment; filename="aklog.c" Content-Transfer-Encoding: 7bit /* aklog.c: request a Kerberos ticket grant for an AFS cell * * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include extern int krb524_convert_creds_kdc(krb5_context, krb5_creds *, CREDENTIALS *); char *realm = "CAMBRIDGE.REDHAT.COM"; //NULL; char *cell = "cambridge.redhat.com"; //NULL; int debug = 0; krb5_principal princ; krb5_context krb5context; krb5_ccache tktcache; static void format(void) __attribute__((noreturn)); static void format(void) { fprintf(stderr, "aklog [-d] [-c] [] [-k ]\n"); exit(2); } #define KRBERR(X,M) do { if ((X) != KSUCCESS) krberr((X),(M)); } while(0) void krberr(errcode_t kerr, const char *where) __attribute__((noreturn)); void krberr(errcode_t kerr, const char *where) { fprintf(stderr, "%s: %s\n", where, error_message(kerr)); exit(1); } /*****************************************************************************/ /* * parse the argument list */ void parse_args(char **argv) { if (!*argv) return; if (strcmp(argv[0], "-help") == 0) format(); if (strcmp(argv[0], "-d") == 0) { debug++; argv++; } if (strcmp(argv[0], "-c") == 0) argv++; if (!*argv) format(); if (argv[0][0] == '-') format(); cell = *argv; argv++; if (!*argv) return; if (strcmp(argv[0], "-k") != 0) format(); argv++; if (!*argv) return; if (argv[0][0] == '-') format(); realm = *argv; argv++; if (*argv) format(); } /* end parse_args() */ /*****************************************************************************/ /* * try to obtain a kerberos ticket */ int obtain_ticket(krb5_creds **creds, const char *service, const char *cell) { krb5_error_code kerr; krb5_creds request; /* set up a description of what we actually want */ memset(&request, 0, sizeof(request)); kerr = krb5_build_principal(krb5context, &request.server, strlen(realm), realm, service, cell, NULL); KRBERR(kerr, "failed to construct request"); request.client = princ; request.times.endtime = 0; request.keyblock.enctype = ENCTYPE_DES_CBC_CRC; /* go and prod the Kerberos servers */ kerr = krb5_get_credentials(krb5context, 0, tktcache, &request, creds); if (kerr != KSUCCESS && kerr != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) KRBERR(kerr, "error talking to KDC"); return kerr == KSUCCESS; } /* end obtain_ticket() */ /*****************************************************************************/ /* * */ int main(int argc, char *argv[]) { krb5_error_code kerr; unsigned char *cp; krb5_creds *creds5; CREDENTIALS creds4; time_t time; char buf1[100]; int loop; parse_args(argv + 1); kerr = krb5_init_context(&krb5context); KRBERR(kerr, "failed to initialise the Kerberos5 context"); /* may need to find the default realm */ if (!realm) { kerr = krb5_get_default_realm(krb5context, &realm); KRBERR(kerr, "failed to get the default realm"); } /* may need to find the default AFS cell */ if (!cell) { } /* open the appropriate Kerberos ticket cache */ kerr = krb5_cc_default(krb5context, &tktcache); KRBERR(kerr, "unable to resolve default cred cache"); kerr = krb5_cc_get_principal(krb5context, tktcache, &princ); KRBERR(kerr, "unable to extract the principal from the cache"); /* ask the KDC to give us an AFS ticket */ if (!cell || !obtain_ticket(&creds5, "afs", cell)) { if (!obtain_ticket(&creds5, "afs", NULL)) { fprintf(stderr, "couldn't obtain AFS ticket\n"); exit(2); } } kerr = krb5_cc_close(krb5context, tktcache); KRBERR(kerr, "error closing cache"); /* ask the KDC to turn the Kerberos 5 ticket into a Kerberos 4 * ticket */ kerr = krb524_convert_creds_kdc(krb5context, creds5, &creds4); KRBERR(kerr, "unable to convert to a kerberos V4 ticket"); /* dump the credential data obtained */ if (debug) { printf("SERVICE : %s%s%s@%s\n", creds4.service, creds4.instance[0] ? "/" : "", creds4.instance, creds4.realm); printf("PRINCIPAL: %s%s%s@%s\n", creds4.pname, creds4.pinst[0] ? "/" : "", creds4.pinst, creds4.realm); time = creds4.issue_date; printf("ISSUED : %s", ctime_r(&time, buf1)); time = creds5->times.endtime; printf("EXPIRES : %s", ctime_r(&time, buf1)); printf("SESSION : key=["); cp = (unsigned char *) &creds4.session; for (loop = 0; loop < sizeof(creds4.session); loop++) printf("%02x", *cp++); printf("]\n"); printf("TICKET : version %d, length %d:", creds4.kvno, creds4.ticket_st.length); cp = (unsigned char *) &creds4.ticket_st.dat; for (loop = 0; loop < creds4.ticket_st.length; loop++) { if (loop % (76 / 2) == 0) printf("\n "); printf("%02x", *cp++); } printf("\n"); } /* pass the ticket to the AFS filesystem */ if (afsutil_authorise_krb5(cell, realm, creds5->times.endtime, sizeof(creds4.session), &creds4.session, creds4.kvno, creds4.ticket_st.length, creds4.ticket_st.dat) < 0 ) { fprintf(stderr, "unable to pass token to kernel: %m\n"); exit(1); } krb5_free_creds(krb5context, creds5); krb5_free_context(krb5context); return 0; } /* end main() */ --Multipart_Wed_Jun_16_15:37:57_2004-1-- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/