/* 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 <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <alloca.h>
#include <sys/prctl.h>

/* 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() */
