keyserv.c revision 36e852a172cba914383d7341c988128b2c667fbd
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
/*
* keyserv - server for storing private encryption keys
* keyserv(1M) performs multiple functions: it stores secret keys per uid; it
* performs public key encryption and decryption operations; and it generates
* "random" keys. keyserv(1M) will talk to no one but a local root process on
* the local transport only.
*/
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <deflt.h>
#include <sys/resource.h>
#include <pwd.h>
#include <rpc/des_crypt.h>
#include <rpc/key_prot.h>
#include <thread.h>
#include <rpcsvc/nis_dhext.h>
#include <syslog.h>
#include <libscf.h>
#include "debug.h"
#include "keyserv_cache.h"
#ifdef KEYSERV_RANDOM
extern long random();
#endif
extern keystatus pk_encrypt();
extern keystatus pk_decrypt();
extern keystatus pk_get_conv_key();
extern bool_t svc_get_local_cred();
extern keystatus pk_setkey3();
extern keystatus pk_encrypt3();
extern keystatus pk_decrypt3();
extern keystatus pk_netput3();
extern keystatus pk_netget3();
extern keystatus pk_get_conv_key3();
extern int init_mechs();
extern int addmasterkey();
extern int storeotherrootkeys();
extern int setdeskeyarray();
extern int getdomainname();
static void randomize();
static void usage();
static void defaults();
static int getrootkey();
static int get_cache_size(char *);
#ifdef DEBUG
extern int test_debug();
extern int real_debug();
int debugging = 1;
#else
int debugging = 0;
#endif
static void keyprogram();
char *getenv();
static char ROOTKEY[] = "/etc/.rootkey";
static char *defaults_file = "/etc/default/keyserv";
static int use_nobody_keys = TRUE;
/*
* Hack to allow the keyserver to use AUTH_DES. The only functions
* that get called are key_encryptsession_pk, key_decryptsession_pk,
* and key_gendes.
*
* The approach is to have the keyserver fill in pointers to local
* implementations of these functions, and to call those in key_call().
*/
extern bool_t (*__key_encryptsession_pk_LOCAL)();
extern bool_t (*__key_decryptsession_pk_LOCAL)();
extern bool_t (*__key_gendes_LOCAL)();
static int nthreads = 32;
/* Disk caching of common keys on by default */
int disk_caching = 1;
mechanism_t **mechs;
/*
* The default size for all types of mech.
* positive integers denote multiples of 1MB
* negative integers denote number of entries
* same goes for non-null entries in cache_size
*/
static int default_cache = 1;
int *cache_size;
char **cache_options;
int
{
extern char *optarg;
extern int optind;
int c, d;
int mode = RPC_SVC_MT_AUTO;
int maxrecsz = RPC_MAXDATASIZE;
void detachfromtty(void);
int setmodulus();
int pk_nodefaultkeys();
int svc_create_local_service();
/*
* Set our allowed number of file descriptors to the max
* of what the system will allow, limited by FD_SETSIZE.
*/
limit = FD_SETSIZE;
}
/*
* Pre-option initialisation
*/
if (geteuid() != 0) {
exit(1);
}
/*
* keyserv will not work with a null domainname.
*/
(domainname[0] == '\0')) {
}
/*
* Initialise security mechanisms
*/
cache_size = NULL;
if (init_mechs() == -1) {
disk_caching = 0;
}
defaults();
switch (c) {
case 'n':
nflag++;
break;
case 'd':
dflag++;
break;
case 'e':
eflag++;
break;
case 'D':
debugging = 1;
break;
case 't':
break;
case 'c':
disk_caching = 0;
break;
case 's':
if (!disk_caching) {
usage();
}
sflag++;
/*
* Which version of [-s] do we have...?
*/
/*
* -s <size>
*/
if (s1flag) {
" [-s <size>]\n");
usage();
}
s1flag++;
break;
}
/*
* -s <mechtype>=<size>[,...]
*/
s2flag++;
while (*options != '\0') {
if (d == -1) {
/* Ignore unknown mechtype */
continue;
}
"missing cache size for "
"mechtype %s\n", cache_options[d]);
usage();
}
}
break;
default:
usage();
break;
}
usage();
}
if (use_nobody_keys == FALSE) {
}
usage();
}
if (!disk_caching && sflag) {
usage();
}
if (debugging) {
if (disk_caching) {
char **cpp = cache_options;
int *ip = cache_size;
if (default_cache < 0) {
abs(default_cache));
} else {
}
if (*ip < 0) {
} else {
}
ip++;
}
} else {
"common key disk caching disabled\n");
}
}
/*
* Post-option initialisation
*/
if (disk_caching) {
int i;
for (i = 0; mechs[i]; i++) {
if ((AUTH_DES_COMPAT_CHK(mechs[i])) ||
continue;
}
}
/*
* Set MT mode
*/
if (nthreads > 0) {
}
/*
* Enable non-blocking mode and maximum record size checks for
* connection oriented transports.
*/
}
"netpath", "keyserv") == 0) {
"%s: unable to create service for version %d\n",
exit(1);
}
"netpath", "keyserv") == 0) {
"%s: unable to create service for version %d\n",
exit(1);
}
"netpath", "keyserv") == 0) {
"%s: unable to create service for version %d\n",
exit(1);
}
if (!debugging) {
}
"%s: unable to create service over doors for version %d\n",
exit(1);
}
"%s: unable to create service over doors for version %d\n",
exit(1);
}
"%s: unable to create service over doors for version %d\n",
exit(1);
}
svc_run();
abort();
/* NOTREACHED */
return (0);
}
/*
* In the event that we don't get a root password, we try to
* randomize the master key the best we can
*/
static void
{
int i;
int seed;
int shift;
seed = 0;
for (i = 0; i < 1024; i++) {
shift = i % 8 * sizeof (int);
}
#ifdef KEYSERV_RANDOM
#else
/* use stupid dangerous bad rand() */
#endif
}
static char *
{
int i = 0;
int rs = 0;
char c;
if (fildes < 0)
return (NULL);
while (i < n - 1) {
switch (rs) {
case 1:
break;
case 0:
/* EOF */
if (i > 0)
s[i] = '\0';
return (NULL);
break;
default:
return (NULL);
}
switch (c) {
case '\0':
break;
case '\n':
s[i] = c;
s[++i] = '\0';
return (s);
default:
if (c != '\0')
s[i++] = c;
}
}
s[i] = '\0';
return (s);
}
/* Should last until 16384-bit DH keys */
#define MAXROOTKEY_LINE_LEN 4224
#define MAXROOTKEY_LEN 4096
#define ROOTKEY_FILE "/etc/.rootkey"
static int
getotherrootkeys(char *name)
{
char line[MAXROOTKEY_LINE_LEN];
char key[MAXROOTKEY_LEN];
int count = 0;
return (0);
count++;
/*
* No encryption algorithm found in the file
* (algtype) so default to DES.
*/
}
continue;
}
return (1);
}
/*
* Try to get root's secret key, by prompting if terminal is a tty, else trying
* from standard input.
* Returns 1 on success.
*/
static int
int prompt;
{
char *passwd;
int passwd2des();
int retval;
if (!getnetname(name)) {
failed to generate host's netname when establishing root's key.\n");
return (0);
}
if (!prompt) {
return (getotherrootkeys(name));
}
/*
* Decrypt yellow pages publickey entry to get secret key
*/
"Can't find %s's secret key\n", name);
return (0);
}
if (secret[0] == 0) {
"Password does not decrypt secret key for %s\n", name);
return (0);
}
"Cannot open %s for write\n", ROOTKEY);
return (0);
}
return (retval);
}
/*
* Procedures to implement RPC service. These procedures are named
* differently from the definitions in key_prot.h (generated by rpcgen)
* because they take different arguments.
*/
char *
{
switch (status) {
case KEY_SUCCESS:
return ("KEY_SUCCESS");
case KEY_NOSECRET:
return ("KEY_NOSECRET");
case KEY_UNKNOWN:
return ("KEY_UNKNOWN");
case KEY_SYSTEMERR:
return ("KEY_SYSTEMERR");
case KEY_BADALG:
return ("KEY_BADALG");
case KEY_BADLEN:
return ("KEY_BADLEN");
default:
return ("(bad result code)");
}
}
{
if (debugging) {
}
if (debugging) {
}
return (TRUE);
}
{
if (debugging) {
}
if (debugging) {
} else {
}
}
return (TRUE);
}
{
if (debugging) {
}
if (debugging) {
} else {
}
}
return (TRUE);
}
{
if (debugging) {
arg->st_priv_key);
};
if (debugging) {
}
return (TRUE);
}
/* ARGSUSED */
void *arg;
{
if (debugging)
if (debugging) {
} else {
}
}
return (TRUE);
}
{
if (debugging)
if (debugging) {
} else {
}
}
return (TRUE);
}
{
if (debugging) {
}
if (debugging) {
} else {
}
}
return (TRUE);
}
{
if (debugging) {
}
if (debugging) {
} else {
}
}
return (TRUE);
}
/* ARGSUSED */
__key_gen_1_svc(v, s, key)
void *v;
struct svc_req *s;
{
int r;
(void) mutex_lock(&keygen_mutex);
DES_ENCRYPT | DES_HW);
if (r != DESERR_NONE && r != DESERR_NOHWDEVICE) {
return (FALSE);
}
if (debugging) {
}
return (TRUE);
}
/* ARGSUSED */
{
} else {
}
if (debugging) {
} else {
}
}
return (TRUE);
}
/*
* Version 3 procedures follow...
*/
static bool_t
{
return (TRUE);
}
static bool_t
{
int len, i;
for (i = 0; i < len; i++) {
dp++;
}
return (TRUE);
}
static bool_t
{
int len, i;
for (i = 0; i < len; i++) {
dp++;
}
return (TRUE);
}
/* ARGSUSED */
static bool_t
{
int i;
res->deskeyarray_val = 0;
return (FALSE);
}
for (i = 0; i < keynum; i++) {
res->deskeyarray_val+i));
res->deskeyarray_val+i);
i, *(int *)(res->deskeyarray_val+i)));
}
return (TRUE);
}
static void
{
}
static bool_t
{
}
static bool_t
{
return (TRUE);
}
static void
{
}
}
static bool_t
{
return (TRUE);
}
static void
{
}
}
static bool_t
{
return (TRUE);
}
static bool_t
{
return (TRUE);
}
static void
{
}
}
static bool_t
{
return (TRUE);
}
/* ARGSUSED */
static bool_t
{
return (TRUE);
}
/*
* RPC boilerplate
*/
static void
{
union {
} argument;
union {
} result;
void (*local_free)() = NULL;
int check_auth;
case NULLPROC:
return;
case KEY_SET:
check_auth = 1;
break;
case KEY_ENCRYPT:
check_auth = 1;
break;
case KEY_DECRYPT:
check_auth = 1;
break;
case KEY_GEN:
check_auth = 0;
break;
case KEY_GETCRED:
check_auth = 0;
break;
case KEY_ENCRYPT_PK:
check_auth = 1;
break;
case KEY_DECRYPT_PK:
check_auth = 1;
break;
case KEY_NET_PUT:
check_auth = 1;
break;
case KEY_NET_GET:
check_auth = 1;
break;
case KEY_GET_CONV:
check_auth = 1;
break;
/*
* Version 3 procedures follow...
*/
case KEY_SET_3:
check_auth = 1;
break;
case KEY_ENCRYPT_3:
check_auth = 1;
break;
case KEY_DECRYPT_3:
check_auth = 1;
break;
case KEY_GEN_3:
check_auth = 0;
break;
case KEY_GETCRED_3:
check_auth = 0;
break;
case KEY_ENCRYPT_PK_3:
check_auth = 1;
break;
case KEY_DECRYPT_PK_3:
check_auth = 1;
break;
case KEY_NET_PUT_3:
check_auth = 1;
break;
case KEY_NET_GET_3:
check_auth = 1;
break;
case KEY_GET_CONV_3:
check_auth = 1;
break;
case KEY_CLEAR_3:
check_auth = 1;
break;
default:
return;
}
if (check_auth) {
if (debugging) {
"not local privileged process\n");
}
return;
}
}
return;
}
if (debugging)
}
if (debugging)
"unable to free arguments\n");
exit(1);
}
if (local_free) {
(*local_free)(&result);
}
}
static bool_t
{
if (debugging)
return (FALSE);
}
if (debugging)
/* LINTED pointer alignment */
} else {
return (TRUE);
}
}
static int
char *size;
{
if (len == 0) {
usage();
}
/*
* cache size in MB
*/
} else {
/*
* negative size indicates number of entries in cache
*/
}
if (csize == 0) {
usage();
}
return (csize);
}
static void
usage()
{
exit(1);
}
static void
defaults(void)
{
register int flags;
register char *ptr;
if (defopen(defaults_file) == 0) {
/*
* ignore case
*/
}
}
}
}