chkey.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
* or http://www.opensolaris.org/os/licensing.
* 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.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <shadow.h>
#include <crypt.h>
#include <sys/types.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/key_prot.h>
#include <rpcsvc/nis.h>
#include <rpcsvc/nis_dhext.h>
#include <rpcsvc/ypclnt.h>
#include <nsswitch.h>
#define PK_FILES 1
#define PK_YP 2
#define PK_LDAP 4
#define CURMECH mechs[mcount]
#define DESCREDPASSLEN sizeof (des_block)
static char CRED_TABLE[] = "cred.org_dir";
static char PKMAP[] = "publickey.byname";
static char PKFILE[] = "/etc/publickey";
#define MAXHOSTNAMELEN 256
#define ROOTKEY_FILE "/etc/.rootkey"
#define ROOTKEY_FILE_BACKUP "/etc/.rootkey.bak"
#define MAXROOTKEY_LINE_LEN 4224 /* Good upto 16384-bit keys */
#define MAXROOTKEY_LEN 4096
/* Should last up to 16384-bit keys */
#define MAXPKENTLEN 8500
bool_t makenew = TRUE; /* Make new keys or reencrypt existing */
bool_t specmech = FALSE; /* Specific mechs requested */
bool_t force = FALSE;
int dest_service = 0; /* To which nameservice do we store key(s) */
char *program_name;
mechanism_t **mechs = NULL; /* List of DH mechanisms */
char **plist = NULL; /* List of public key(s) */
char **slist = NULL; /* List of secret key(s) */
char **clist = NULL; /* List of encrypted secret key(s) */
int numspecmech = 0; /* Number of mechanisms specified */
struct passwd *pw = NULL; /* passwd entry of user */
struct spwd *spw = NULL; /* shadow entry of user */
char *netname = NULL; /* RPC netname of user */
char local_domain[MAXNETNAMELEN + 1];
char *sec_domain = NULL;
char **rpc_pws = NULL; /* List of S-RPC passwords */
int rpc_pw_count = 0; /* Number of passwords entered by user */
char *login_pw = NULL; /* Unencrypted login password */
char short_login_pw[DESCREDPASSLEN + 1];
/* Short S-RPC password, which has first 8 chars of login_pw */
static int add_cred_obj(nis_object *, char *);
static void cmp_passwd();
static void encryptkeys();
static void error_msg();
static char *fgets_ignorenul();
static void getpublics();
static void getrpcpws();
static void getsecrets();
static void initkeylist(bool_t);
static void keylogin(keylen_t, algtype_t);
static void keylogin_des();
static void makenewkeys();
static int modify_cred_obj(nis_object *, char *);
static void storekeys();
static void usage();
static void write_rootkey();
extern nis_object *init_entry();
extern int get_pk_source(char *);
extern int localupdate(char *, char *, uint_t, char *);
extern int xencrypt();
extern int xencrypt_g();
extern int __gen_dhkeys();
extern int key_setnet();
extern int key_setnet_g();
extern int key_secretkey_is_set_g();
extern int __getnetnamebyuid();
extern int getdomainname();
extern int ldap_update(char *, char *, char *, char *, char *);
static void
error_msg()
{
if (sec_domain && *sec_domain &&
strcasecmp(sec_domain, local_domain)) {
fprintf(stderr,
"The system default domain '%s' is different from the Secure RPC\n\
domain %s where the key is stored. \n", local_domain, sec_domain);
exit(1);
}
}
static void
usage()
{
fprintf(stderr, "usage: %s [-p] [-s ldap | nis | files] \n",
program_name);
exit(1);
}
/* Encrypt secret key(s) with login_pw */
static void
encryptkeys()
{
int mcount, ccount = 0;
if (mechs) {
for (mcount = 0; CURMECH; mcount++) {
char *crypt = NULL;
if (!xencrypt_g(slist[mcount], CURMECH->keylen,
CURMECH->algtype, short_login_pw, netname,
&crypt, TRUE)) {
/* Could not crypt key */
crypt = NULL;
} else
ccount++;
clist[mcount] = crypt;
}
} else {
char *crypt = NULL;
if (!(crypt =
(char *)malloc(HEXKEYBYTES + KEYCHECKSUMSIZE + 1))) {
fprintf(stderr, "%s: Malloc failure.\n", program_name);
exit(1);
}
(void) memcpy(crypt, slist[0], HEXKEYBYTES);
(void) memcpy(crypt + HEXKEYBYTES, slist[0], KEYCHECKSUMSIZE);
crypt[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0;
xencrypt(crypt, short_login_pw);
clist[0] = crypt;
ccount++;
}
if (!ccount) {
fprintf(stderr, "%s: Could not encrypt any secret keys.\n",
program_name);
exit(1);
}
}
/* Initialize the array of public, secret, and encrypted secret keys */
static void
initkeylist(bool_t nomech)
{
int mcount;
if (!nomech) {
assert(mechs && mechs[0]);
for (mcount = 0; CURMECH; mcount++)
;
} else
mcount = 1;
if (!(plist = (char **)malloc(sizeof (char *) * mcount))) {
fprintf(stderr, "%s: Malloc failure.\n", program_name);
exit(1);
}
if (!(slist = (char **)malloc(sizeof (char *) * mcount))) {
fprintf(stderr, "%s: Malloc failure.\n", program_name);
exit(1);
}
if (!(clist = (char **)malloc(sizeof (char *) * mcount))) {
fprintf(stderr, "%s: Malloc failure.\n", program_name);
exit(1);
}
}
/* Retrieve public key(s) */
static void
getpublics()
{
int mcount;
int pcount = 0;
if (mechs) {
for (mcount = 0; CURMECH; mcount++) {
char *public;
size_t hexkeylen;
hexkeylen = ((CURMECH->keylen / 8) * 2) + 1;
if (!(public = (char *)malloc(hexkeylen))) {
fprintf(stderr, "%s: Malloc failure.\n",
program_name);
exit(1);
}
if (!getpublickey_g(netname, CURMECH->keylen,
CURMECH->algtype, public,
hexkeylen)) {
/* Could not get public key */
fprintf(stderr,
"Could not get %s public key.\n",
VALID_ALIAS(CURMECH->alias) ?
CURMECH->alias : "");
free(public);
public = NULL;
} else
pcount++;
plist[mcount] = public;
}
} else {
char *public;
if (!(public = (char *)malloc(HEXKEYBYTES + 1))) {
fprintf(stderr, "%s: Malloc failure.\n", program_name);
exit(1);
}
if (!getpublickey(netname, public)) {
free(public);
public = NULL;
} else
pcount++;
plist[0] = public;
}
if (!pcount) {
fprintf(stderr, "%s: cannot get any public keys for %s.\n",
program_name, pw->pw_name);
error_msg();
fprintf(stderr,
"Make sure that the public keys are stored in the domain %s.\n",
local_domain);
exit(1);
}
}
/* Generate a new set of public/secret key pair(s) */
static void
makenewkeys()
{
int mcount;
if (mechs) {
for (mcount = 0; CURMECH; mcount++) {
char *public, *secret;
size_t hexkeylen;
if (slist[mcount])
free(slist[mcount]);
hexkeylen = ((CURMECH->keylen / 8) * 2) + 1;
if (!(public = malloc(hexkeylen))) {
fprintf(stderr, "%s: Malloc failure.\n",
program_name);
exit(1);
}
if (!(secret = malloc(hexkeylen))) {
fprintf(stderr, "%s: Malloc failure.\n",
program_name);
exit(1);
}
if (!(__gen_dhkeys_g(public, secret, CURMECH->keylen,
CURMECH->algtype, short_login_pw))) {
/* Could not generate key pair */
fprintf(stderr,
"WARNING Could not generate key pair %s\n",
VALID_ALIAS(CURMECH->alias) ?
CURMECH->alias : "");
free(public);
free(secret);
public = NULL;
secret = NULL;
}
plist[mcount] = public;
slist[mcount] = secret;
}
} else {
char *public, *secret;
if (slist[0])
free(slist[0]);
if (!(public = malloc(HEXKEYBYTES + 1))) {
fprintf(stderr, "%s: Malloc failure.\n", program_name);
exit(1);
}
if (!(secret = malloc(HEXKEYBYTES + 1))) {
fprintf(stderr, "%s: Malloc failure.\n", program_name);
exit(1);
}
__gen_dhkeys(public, secret, short_login_pw);
plist[0] = public;
slist[0] = secret;
}
}
/*
* Make sure that the entered Secure-RPC password(s) match the login
* password
*/
static void
cmp_passwd()
{
char baseprompt[] = "Please enter the login password for";
char prompt[BUFSIZ];
char *en_login_pw = spw->sp_pwdp;
char short_en_login_pw[DESCREDPASSLEN + 1];
char *try_en_login_pw;
bool_t pwmatch = FALSE;
int done = 0, tries = 0, pcount;
snprintf(prompt, BUFSIZ, "%s %s:", baseprompt, pw->pw_name);
(void) strlcpy(short_en_login_pw, en_login_pw,
sizeof (short_en_login_pw));
if (en_login_pw && (strlen(en_login_pw) != 0)) {
for (pcount = 0; pcount < rpc_pw_count; pcount++) {
char *try_en_rpc_pw;
try_en_rpc_pw = crypt(rpc_pws[pcount], short_en_login_pw);
if (strcmp(try_en_rpc_pw, short_en_login_pw) == 0) {
login_pw = rpc_pws[pcount];
(void) strlcpy(short_login_pw, login_pw,
sizeof (short_login_pw));
pwmatch = TRUE;
break;
}
}
if (!pwmatch) {
/* pw don't match */
while (!done) {
/* ask for the pw */
login_pw = getpassphrase(prompt);
(void) strlcpy(short_login_pw, login_pw,
sizeof (short_login_pw));
if (login_pw && strlen(login_pw)) {
/* pw was not empty */
try_en_login_pw = crypt(login_pw,
en_login_pw);
/* compare the pw's */
if (!(strcmp(try_en_login_pw,
en_login_pw))) {
/* pw was correct */
return;
} else {
/* pw was wrong */
if (tries++) {
/* Sorry */
fprintf(stderr,
"Sorry.\n");
exit(1);
} else {
/* Try again */
snprintf(prompt,
BUFSIZ,
"Try again. %s %s:",
baseprompt,
pw->pw_name);
}
}
} else {
/* pw was empty */
if (tries++) {
/* Unchanged */
fprintf(stderr,
"%s: key-pair(s) unchanged for %s.\n",
program_name,
pw->pw_name);
exit(1);
} else {
/* Need a password */
snprintf(prompt, BUFSIZ,
"Need a password. %s %s:",
baseprompt,
pw->pw_name);
}
}
}
}
/* pw match */
return;
} else {
/* no pw found */
fprintf(stderr,
"%s: no passwd found for %s in the shadow passwd entry.\n",
program_name, pw->pw_name);
exit(1);
}
}
/* Prompt the user for a Secure-RPC password and store it in a cache. */
static void
getrpcpws(char *flavor)
{
char *cur_pw = NULL;
char prompt[BUFSIZ + 1];
if (flavor)
snprintf(prompt, BUFSIZ,
"Please enter the %s Secure-RPC password for %s:",
flavor, pw->pw_name);
else
snprintf(prompt, BUFSIZ,
"Please enter the Secure-RPC password for %s:",
pw->pw_name);
cur_pw = getpass(prompt);
if (!cur_pw) {
/* No changes */
fprintf(stderr, "%s: key-pair(s) unchanged for %s.\n",
program_name, pw->pw_name);
exit(1);
}
rpc_pw_count++;
if (!(rpc_pws =
(char **)realloc(rpc_pws, sizeof (char *) * rpc_pw_count))) {
fprintf(stderr, "%s: Realloc failure.\n", program_name);
exit(1);
}
rpc_pws[rpc_pw_count - 1] = cur_pw;
}
/* Retrieve the secret key(s) for the user and attempt to decrypt them */
static void
getsecrets()
{
int mcount, scount = 0;
int tries = 0;
getrpcpws(NULL);
if (mechs) {
for (mcount = 0; CURMECH; mcount++) {
char *secret;
int pcount;
size_t hexkeylen;
hexkeylen = ((CURMECH->keylen / 8) * 2) + 1;
if (!(secret = (char *)calloc(hexkeylen,
sizeof (char)))) {
fprintf(stderr, "%s: Malloc failure.\n",
program_name);
exit(1);
}
for (pcount = 0; pcount < rpc_pw_count; pcount++) {
if (!getsecretkey_g(netname, CURMECH->keylen,
CURMECH->algtype, secret,
hexkeylen,
rpc_pws[pcount]))
continue;
if (secret[0] == 0)
continue;
else
break;
}
tries = 0;
getsecrets_tryagain_g:
if (secret[0] == 0) {
if (!tries) {
/*
* No existing pw can decrypt
* secret key
*/
getrpcpws(CURMECH->alias);
if (!getsecretkey_g(netname,
CURMECH->keylen,
CURMECH->algtype,
secret,
hexkeylen,
rpc_pws[pcount])) {
/*
* Could not retreive
* secret key, abort
*/
free(secret);
secret = NULL;
goto getsecrets_abort;
}
if (secret[0] == 0) {
/* Still no go, ask again */
free(rpc_pws[pcount]);
rpc_pw_count--;
tries++;
printf("Try again. ");
fflush(stdout);
goto getsecrets_tryagain_g;
} else
scount++;
} else {
fprintf(stderr,
"%s: key-pair unchanged for %s.\n",
program_name, pw->pw_name);
exit(1);
}
} else
scount++;
getsecrets_abort:
slist[mcount] = secret;
}
} else {
char *secret = NULL;
if (!(secret = (char *)malloc(HEXKEYBYTES + 1))) {
fprintf(stderr, "%s: Malloc failure.\n", program_name);
exit(1);
}
getsecrets_tryagain:
if (!getsecretkey(netname, secret, rpc_pws[0])) {
fprintf(stderr,
"%s: could not get secret key for '%s'\n",
program_name, netname);
exit(1);
}
if (secret[0] == 0) {
if (!tries) {
free(rpc_pws[0]);
rpc_pw_count = 0;
tries++;
printf("Try again. ");
fflush(stdout);
getrpcpws(NULL);
goto getsecrets_tryagain;
} else {
fprintf(stderr,
"%s: key-pair unchanged for %s.\n",
program_name, pw->pw_name);
exit(1);
}
}
slist[0] = secret;
return;
}
if (!scount) {
(void) fprintf(stderr,
"%s: could not get nor decrypt any secret keys for '%s'\n",
program_name, netname);
error_msg();
exit(1);
}
}
/* Register AUTH_DES secret key with keyserv */
static void
keylogin_des()
{
char *secret = slist[0];
struct key_netstarg netst;
/*
* try to revoke the existing key/credentials, assuming
* one exists. this will effectively mark "stale" any
* cached credientials...
*/
if (key_setsecret(secret) < 0) {
return;
}
#ifdef NFS_AUTH
/*
* it looks like a credential already existed, so try and
* revoke any lingering Secure-NFS privledges.
*/
nra.authtype = AUTH_DES;
nra.uid = getuid();
if (_nfssys(NFS_REVAUTH, &nra) < 0)
perror("Warning: NFS credentials not destroyed");
#endif /* NFS_AUTH */
(void) memcpy(netst.st_priv_key, secret, HEXKEYBYTES);
netst.st_pub_key[0] = '\0';
netst.st_netname = strdup(netname);
/* do actual key login */
if (key_setnet(&netst) < 0) {
fprintf(stderr, "Could not set %s's secret key\n", netname);
fprintf(stderr, "May be the keyserv is down?\n");
}
}
/* Register a secret key with the keyserv */
static void
keylogin(keylen_t keylen, algtype_t algtype)
{
int mcount;
if (mechs) {
for (mcount = 0; CURMECH; mcount++) {
if (keylen == CURMECH->keylen &&
algtype == CURMECH->algtype) {
if (key_setnet_g(netname, slist[mcount],
CURMECH->keylen,
NULL, 0,
CURMECH->algtype)
< 0)
fprintf(stderr,
"Could not set %s's %s secret key\n",
netname,
VALID_ALIAS(CURMECH->alias) ?
CURMECH->alias : "");
}
}
} else {
if (keylen == 192 && algtype == 0)
keylogin_des();
}
}
/*
* fgets is "broken" in that if it reads a NUL character it will
* always return EOF for all reads, even when there is data left in
* the file. This replacement can deal with NUL's in a calm, rational
* manner.
*/
static char *
fgets_ignorenul(char *s, int n, FILE *stream)
{
int fildes = fileno(stream);
int i = 0;
int rs = 0;
char c;
if (fildes < 0)
return (NULL);
while (i < n - 1) {
rs = read(fildes, &c, 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);
}
/* Write unencrypted secret key into root key file */
static void
write_rootkey(char *secret, char *flavor, keylen_t keylen, algtype_t algtype)
{
char line[MAXROOTKEY_LINE_LEN];
char keyent[MAXROOTKEY_LEN];
algtype_t atent;
int rootfd, bakfd, hexkeybytes;
bool_t lineone = TRUE;
bool_t gotit = FALSE;
FILE *rootfile, *bakfile;
unlink(ROOTKEY_FILE_BACKUP);
if ((rename(ROOTKEY_FILE, ROOTKEY_FILE_BACKUP)) < 0) {
if ((bakfd = creat(ROOTKEY_FILE_BACKUP, 0600)) < 0) {
perror("Could not create /etc/.rootkey.bak");
goto rootkey_err;
}
close(bakfd);
}
if ((rootfd = open(ROOTKEY_FILE, O_WRONLY+O_CREAT, 0600)) < 0) {
perror("Could not open /etc/.rootkey for writing");
fprintf(stderr,
"Attempting to restore original /etc/.rootkey\n");
rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE);
goto rootkey_err;
}
if (!(rootfile = fdopen(rootfd, "w"))) {
perror("Could not open /etc/.rootkey for writing");
fprintf(stderr,
"Attempting to restore original /etc/.rootkey\n");
close(rootfd);
unlink(ROOTKEY_FILE);
rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE);
goto rootkey_err;
}
if (!(bakfile = fopen(ROOTKEY_FILE_BACKUP, "r"))) {
perror("Could not open /etc/.rootkey.bak for reading");
fprintf(stderr,
"Attempting to restore original /etc/.rootkey\n");
fclose(rootfile);
unlink(ROOTKEY_FILE);
rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE);
goto rootkey_err;
}
hexkeybytes = ((keylen + 7) / 8) * 2;
while (fgets_ignorenul(line, MAXROOTKEY_LINE_LEN, bakfile)) {
if (sscanf(line, "%s %d", keyent, &atent) < 2) {
/*
* No encryption algorithm found in the file
* (atent) so default to DES.
*/
atent = AUTH_DES_ALGTYPE;
}
/*
* 192-bit keys always go on the first line
*/
if (lineone) {
lineone = FALSE;
if (keylen == 192) {
gotit = TRUE;
fprintf(rootfile, "%s\n", secret);
} else
fprintf(rootfile, "%s", line);
fflush(rootfile);
} else {
if ((strlen(keyent) == hexkeybytes) &&
(atent == algtype)) {
/*
* Silently remove lines with the same
* keylen/algtype
*/
if (gotit)
continue;
else
gotit = TRUE;
fprintf(rootfile, "%s %d\n", secret, algtype);
} else
fprintf(rootfile, "%s", line);
fflush(rootfile);
}
}
/* Append key to rootkey file */
if (!gotit) {
if (keylen == 192)
fprintf(rootfile, "%s\n", secret);
else {
if (lineone)
fprintf(rootfile, "\n");
fprintf(rootfile, "%s %d\n", secret, algtype);
}
}
fflush(rootfile);
fclose(rootfile);
fclose(bakfile);
unlink(ROOTKEY_FILE_BACKUP);
return;
rootkey_err:
fprintf(stderr, "WARNING: Could not write %s key to /etc/.rootkey\n",
flavor);
}
/* Store new key information in the specified name service */
static void
storekeys()
{
int mcount, ucount = 0;
char *ypmaster, *ypdomain = NULL, pkent[MAXPKENTLEN];
nis_name nis_princ;
/* Setup */
switch (dest_service) {
case PK_LDAP:
break;
case PK_YP:
yp_get_default_domain(&ypdomain);
if (yp_master(ypdomain, PKMAP, &ypmaster) != 0) {
fprintf(stderr,
"%s: cannot find master of NIS publickey database\n",
program_name);
exit(1);
}
fprintf(stdout,
"Sending key change request to %s ...\n", ypmaster);
break;
case PK_FILES:
if (geteuid() != 0) {
fprintf(stderr,
"%s: non-root users cannot change their key-pair in %s\n",
program_name, PKFILE);
exit(1);
}
break;
default:
fprintf(stderr,
"could not update; database %d unknown\n",
dest_service);
exit(1);
}
if (mechs) {
for (mcount = 0; CURMECH; mcount++) {
char authtype[MECH_MAXATNAME];
if (!plist[mcount] && !clist[mcount])
continue;
__nis_mechalias2authtype(CURMECH->alias, authtype,
MECH_MAXATNAME);
if (!authtype) {
fprintf(stderr,
"Could not generate auth_type for %s.\n",
CURMECH->alias);
continue;
}
snprintf(pkent, MAXPKENTLEN, "%s:%s:%d",
plist[mcount], clist[mcount],
CURMECH->algtype);
switch (dest_service) {
case PK_LDAP:
if (ldap_update(CURMECH->alias, netname,
plist[mcount], clist[mcount],
login_pw))
fprintf(stderr,
"%s: unable to update %s key in LDAP database\n",
program_name, authtype);
else
ucount++;
break;
case PK_YP:
/* Should never get here. */
break;
case PK_FILES:
/* Should never get here. */
break;
}
}
} else {
int status = 0;
assert(plist[0] && clist[0]);
snprintf(pkent, MAXPKENTLEN, "%s:%s", plist[0], clist[0]);
switch (dest_service) {
case PK_LDAP:
if (ldap_update("dh192-0", netname,
plist[0], clist[0],
login_pw)) {
fprintf(stderr,
"%s: unable to update %s key in LDAP database\n",
program_name);
exit(1);
}
break;
case PK_YP:
if (status = yp_update(ypdomain, PKMAP,
YPOP_STORE, netname,
strlen(netname), pkent,
strlen(pkent))) {
fprintf(stderr,
"%s: unable to update NIS database (%u): %s\n",
program_name, status,
yperr_string(status));
exit(1);
}
break;
case PK_FILES:
if (localupdate(netname, PKFILE, YPOP_STORE, pkent)) {
fprintf(stderr,
"%s: hence, unable to update publickey database\n",
program_name);
exit(1);
}
break;
default:
/* Should never get here */
assert(0);
}
return;
}
if (!ucount) {
fprintf(stderr, "%s: unable to update any key-pairs for %s.\n",
program_name, pw->pw_name);
exit(1);
}
}
void
addmechtolist(char *mechtype)
{
mechanism_t **realmechlist;
int i;
if (realmechlist = __nis_get_mechanisms(FALSE)) {
/* Match requested mech with list */
for (i = 0; realmechlist[i]; i++) {
if (realmechlist[i]->alias)
if (strcmp(realmechlist[i]->alias, mechtype)
== 0) {
/*
* Match, add it to the mechs.
* Don't worry about qop or
* secserv since they are not
* used by chkey.
*/
numspecmech++;
if ((mechs =
(mechanism_t **)realloc(mechs,
sizeof (mechanism_t *) *
(numspecmech + 1))) == NULL) {
perror("Can not change keys");
exit(1);
}
if ((mechs[numspecmech - 1] =
(mechanism_t *)malloc(
sizeof (mechanism_t))) == NULL) {
perror("Can not change keys");
exit(1);
}
if (realmechlist[i]->mechname)
mechs[numspecmech - 1]->mechname =
strdup(realmechlist[i]->mechname);
if (realmechlist[i]->alias)
mechs[numspecmech - 1]->alias =
strdup(realmechlist[i]->alias);
mechs[numspecmech - 1]->keylen =
realmechlist[i]->keylen;
mechs[numspecmech - 1]->algtype =
realmechlist[i]->algtype;
mechs[numspecmech] = NULL;
__nis_release_mechanisms(realmechlist);
return;
}
}
fprintf(stderr,
"WARNING: Mechanism '%s' not configured, skipping...\n",
mechtype);
__nis_release_mechanisms(realmechlist);
return;
}
fprintf(stderr,
"WARNING: Mechanism '%s' not configured, skipping...\n",
mechtype);
}
int
main(int argc, char **argv)
{
int c, mcount;
uid_t uid;
uid_t orig_euid;
char *service = NULL;
program_name = argv[0];
mechs = __nis_get_mechanisms(FALSE);
while ((c = getopt(argc, argv, "fps:m:")) != -1) {
switch (c) {
case 'f':
/*
* Not documented as of on1093.
* Temporarily supported
*/
force++;
break;
case 'p':
makenew = FALSE;
break;
case 's':
if (!service)
service = strdup(optarg);
else
usage();
break;
case 'm':
if (mechs && specmech == FALSE) {
__nis_release_mechanisms(mechs);
mechs = NULL;
}
specmech = TRUE;
addmechtolist(optarg);
break;
default:
usage();
}
}
if (optind < argc)
usage();
dest_service = get_pk_source(service);
if (!(netname = malloc(MAXNETNAMELEN + 1))) {
fprintf(stderr, "%s: Malloc failure.\n", program_name);
exit(1);
}
if (!__getnetnamebyuid(netname, uid = getuid())) {
fprintf(stderr, "%s: cannot generate netname for uid %d\n",
program_name, uid);
exit(1);
}
sec_domain = strdup(strchr(netname, '@') + 1);
getdomainname(local_domain, MAXNETNAMELEN);
if (makenew)
fprintf(stdout, "Generating new key for '%s'.\n", netname);
else
fprintf(stdout, "Reencrypting key for '%s'.\n", netname);
if (mechs) {
if (dest_service == PK_YP || dest_service == PK_FILES) {
fprintf(stderr,
"%s: can not add non-DES public keys to %s, skipping.\n",
program_name, service);
__nis_release_mechanisms(mechs);
mechs = NULL;
initkeylist(TRUE);
} else
initkeylist(FALSE);
} else
initkeylist(TRUE);
uid = getuid();
orig_euid = geteuid();
/* Get password information */
if ((pw = getpwuid(uid)) == NULL) {
fprintf(stderr,
"%s: Can not find passwd information for %d.\n",
program_name, uid);
exit(1);
}
/* Set eUID to user */
seteuid(uid);
/* Obtain a list of decrypted secret keys */
getsecrets();
/* Keylogin user if not already done */
if (mechs) {
int mcount;
for (mcount = 0; CURMECH; mcount++) {
keylen_t keylen = CURMECH->keylen;
algtype_t algtype = CURMECH->algtype;
if (!key_secretkey_is_set_g(keylen, algtype) &&
slist[mcount]) {
keylogin(CURMECH->keylen, CURMECH->algtype);
if ((uid == 0) && (makenew == FALSE))
write_rootkey(slist[mcount],
VALID_ALIAS(CURMECH->alias) ?
CURMECH->alias :
"",
keylen, algtype);
}
}
} else {
assert(slist[0]);
if (!key_secretkey_is_set()) {
keylogin_des();
if ((uid == 0) && (makenew == FALSE))
write_rootkey(slist[0], "des", 192, 0);
}
}
/* Set eUID back to root */
(void) seteuid(orig_euid);
/*
* Call getspnam() after the keylogin has been done so we have
* the best chance of having read access to the encrypted pw.
*
* The eUID must be 0 for the getspnam() so the name service
* switch can handle the following eUID sensitive cases:
*
* files/compat: read /etc/shadow
*
*/
if ((spw = getspnam(pw->pw_name)) == 0) {
/* Set eUID back to user */
(void) seteuid(uid);
(void) fprintf(stderr,
"%s: cannot find shadow entry for %s.\n",
program_name, pw->pw_name);
exit(1);
}
/* Set eUID back to user */
(void) seteuid(uid);
if (strcmp(spw->sp_pwdp, NOPWDRTR) == 0) {
(void) fprintf(stderr,
"%s: do not have read access to the passwd field for %s\n",
program_name, pw->pw_name);
exit(1);
}
/*
* force will be only supported for a while
* -- it is NOT documented as of s1093
*/
if (force) {
char *prompt = "Please enter New password:";
login_pw = getpassphrase(prompt);
(void) strlcpy(short_login_pw, login_pw,
sizeof (short_login_pw));
if (!login_pw || !(strlen(login_pw))) {
fprintf(stderr, "%s: key-pair(s) unchanged for %s.\n",
program_name, pw->pw_name);
exit(1);
}
} else {
/*
* Reconsile rpc_pws and login_pw.
*
* This function will either return with login_pw == rpc_pw
* (and thus, the new pw to encrypt keys) or it will exit.
*/
cmp_passwd();
}
if (makenew)
makenewkeys();
else
getpublics();
encryptkeys();
storekeys();
if (makenew) {
if (uid == 0) {
if (mechs) {
for (mcount = 0; CURMECH; mcount++) {
if (!slist[mcount])
continue;
write_rootkey(slist[mcount],
CURMECH->alias,
CURMECH->keylen,
CURMECH->algtype);
}
} else {
assert(slist[0]);
write_rootkey(slist[0], "des", 192, 0);
}
}
if (mechs) {
for (mcount = 0; CURMECH; mcount++)
keylogin(CURMECH->keylen,
CURMECH->algtype);
} else
keylogin_des();
}
return (0);
}