chkey_common.c revision 49e7ca4919cec3229f6fab9730bafc7cf24dab23
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include <pwd.h>
#include <shadow.h>
#include <netdb.h>
#include <mp.h>
#include <rpc/key_prot.h>
#include <nsswitch.h>
#include <ns_sldap.h>
extern char *crypt();
extern long random();
extern char *getpassphrase();
extern char *program_name;
static const char *CRED_TABLE = "cred.org_dir";
#define ROOTKEY_FILE "/etc/.rootkey"
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
#define PK_FILES 1
#define PK_YP 2
#define PK_NISPLUS 3
#define PK_LDAP 4
#define LDAP_BINDDN_DEFAULT "cn=Directory Manager"
#define PROMPTGET_SUCCESS 1
#define PROMPTGET_FAIL -1
#define PROMPTGET_MEMORY_FAIL -2
#define PASSWD_UNMATCHED -3
#define FREE_CREDINFO(s) \
/* ************************ switch functions *************************** */
/* NSW_NOTSUCCESS NSW_NOTFOUND NSW_UNAVAIL NSW_TRYAGAIN */
static struct __nsw_switchconfig publickey_default =
static int get_ldap_bindDN(char **);
static int get_ldap_bindPassword(char **);
/*
* Prompt the users for a ldap bind DN. If users do not enter a value but just
* simply hit the return key, the default bindDN "cn=Directory Manager"
* will be used.
*/
static int
get_ldap_bindDN(char **ret_bindDN) {
/* set the initial value for bindDN buffer */
"\nThe LDAP bind DN and password are required for this update.\n"
"If you are not sure what values to enter, please contact your\n"
"LDAP administrator.\n\nPlease enter LDAP bind DN [%s]: ",
}
/* Check if the buffer ends with a newline */
blen -= 1;
}
/* Remove the white spaces */
if (blen > 0) {
else
break;
}
}
/* Use the default bindDN, if the buffer contains no characters */
return (PROMPTGET_MEMORY_FAIL);
}
/* Clean up and erase the credential info */
return (PROMPTGET_SUCCESS);
}
/*
* Prompt the user for a ldap bind password.
*/
static int
get_ldap_bindPassword(char **ret_bindPass) {
char bindPassword[BUFSIZ];
/* set the initial value for bindPassword buffer */
*ret_bindPass = NULL;
"Please enter LDAP bind password: ");
return (PROMPTGET_FAIL);
/* clean the static buffer returned from getpassphrase call */
/*
* Re-enter the bind passowrd and compare it with the one
* from previous entered.
*/
"Re-enter LDAP bind password to confirm: ");
return (PASSWD_UNMATCHED);
}
return (PASSWD_UNMATCHED);
} else {
== NULL) {
return (PROMPTGET_MEMORY_FAIL);
}
/* Clean up and erase the credential info */
return (PROMPTGET_SUCCESS);
}
}
char *
{
struct __nsw_lookup *look;
int previous = 0;
if (previous)
previous = 1;
}
return (policy);
}
int
{
}
int
{
return (conf &&
}
char *
struct __nsw_switchconfig *default_conf,
char *head_msg)
{
struct __nsw_switchconfig *conf;
enum __nsw_parse_err perr;
int policy_correct = 1;
char *target_service = 0;
int use_default = 0;
if (default_conf == 0)
if (no_switch_policy(conf)) {
use_default = 1;
conf = default_conf;
}
policy_correct = 0;
if (use_default) {
"\n%s\n There is no publickey entry in %s.\n",
"The default publickey policy is \"publickey: %s\".\n",
} else
"\n%s\nThe publickey entry in %s is \"publickey: %s\".\n",
}
if (policy_correct == 0)
"I cannot figure out which publickey database you want to update.\n");
if (!use_default && conf)
if (policy_correct)
return (target_service);
else
return (0);
}
int
struct __nsw_switchconfig *default_conf,
{
struct __nsw_switchconfig *conf;
enum __nsw_parse_err perr;
int policy_correct = 1;
if (default_conf == 0)
if (no_switch_policy(conf)) {
"\n%s\nThere is no publickey entry in %s.\n",
"The default publickey policy is \"publickey: %s\".\n",
policy_correct = 0;
}
"\n%s\nThe publickey entry in %s is \"publickey: %s\".\n",
policy_correct = 0;
}
/* should we exit ? */
if (policy_correct == 0)
"It should be \"publickey: %s\"%s\n\n",
if (conf)
return (policy_correct);
}
int
get_pk_source(char *pk_service)
{
int db = 0, got_from_switch = 0;
/* No service specified, try to figure out from switch */
if (pk_service == 0) {
"ERROR:");
if (pk_service == 0)
return (0);
"Updating %s publickey database.\n",
got_from_switch = 1;
}
db = PK_NISPLUS;
else return (0);
/*
* If we didn't get service name from switch, check switch
* and print warning about it source of publickeys if not unique
*/
if (got_from_switch == 0)
"; add 'files' if you want the 'nobody' key.");
return (db); /* all passed */
}
/* ***************************** keylogin stuff *************************** */
int
{
struct key_netstarg netst;
netst.st_pub_key[0] = 0;
#ifdef NFS_AUTH
perror("Warning: NFS credentials not destroyed");
err = 1;
}
#endif
/* do actual key login */
if (key_setnet(&netst) < 0) {
"Could not set %s's secret key\n", netname);
return (0);
}
return (1);
}
/*
* XXX unused routine.
* Can not locate any routine that is using this write_rootkey()
* function. There are 2 other write_rootkey() routines defined in chkey.c
* and in cmd/rpcsvc/nis/utils/nisaddcred/makedhextcred.c.
*
* write unencrypted secret key into root key file
*/
void
write_rootkey(char *secret)
{
} else {
}
}
/* ****************************** nisplus stuff ************************* */
/* most of it gotten from nisaddcred */
/* Check that someone else don't have the same auth information already */
static
{
char *foundprinc;
/* Don't want FOLLOW_PATH here */
case NIS_NOTFOUND:
break;
case NIS_TRYAGAIN :
"%s: NIS+ server busy, try again later.\n",
exit(1);
case NIS_PERMISSION :
"%s: insufficient permission to look up old credentials.\n",
exit(1);
case NIS_SUCCESS:
"%s: %s credentials with auth_name '%s' already belong to '%s'.\n",
exit(1);
}
break;
default:
"%s: error looking at cred table, NIS+ error: %s\n",
exit(1);
}
return (status);
}
/* Returns 0 if check fails; 1 if successful. */
static int
char *nis_princ,
*netname,
*domain;
{
char *princdomain, *netdomain;
int len;
/* Sanity check 0. Do we have a nis+ principal name to work with? */
"%s: you must create a \"LOCAL\" credential for '%s' first.\n",
return (0);
}
/* Sanity check 0.5. NIS+ principal names must be dotted. */
"%s: invalid principal name: '%s' (forgot ending dot?).\n",
return (0);
}
/* Sanity check 1. We only deal with one type of netnames. */
"%s: unrecognized netname type: '%s'.\n",
return (0);
}
/* Sanity check 2. Should only add DES cred in home domain. */
"%s: domain of principal '%s' does not match destination domain '%s'.\n",
"Should only add DES credential of principal in its home domain\n");
return (0);
}
/*
* Sanity check 3: Make sure netname's domain same as principal's
* and don't have extraneous dot at the end.
*/
return (0);
}
netdomain++; /* skip '@' */
/* make sure we don't run into buffer overflow */
return (0);
"%s: domain of netname %s should be same as that of principal %s\n",
return (0);
}
/* Another principal owns same credentials? (exits if that happens) */
return (1); /* all passed */
}
/*
* Similar to nis_local_principal in "nis_subr.c" except
* this gets the results from the MASTER_ONLY and no FOLLOW_PATH.
* We only want the master because we'll be making updates there,
* and also the replicas may not have seen the 'nisaddacred local'
* that may have just occurred.
* Returns NULL if not found.
*/
char *
char *directory;
{
int status;
if (uid == 0)
return (nis_local_host());
/* buf is enough to hold the string, no buffer overflow */
"%s: unable to get result from NIS+ server.",
exit(1);
}
case NIS_SUCCESS:
/*
* More than one principal with same uid?
* something wrong with cred table. Should be unique
* Warn user and continue.
*/
"%s: LOCAL entry for %d in directory %s not unique",
}
/* make sure we don't run into buffer overflow */
sizeof (principal_name))
return (NULL);
return (principal_name);
case NIS_NOTFOUND:
return (NULL);
case NIS_TRYAGAIN :
"%s: NIS+ server busy, try again later.\n",
exit(1);
case NIS_PERMISSION :
"%s: insufficient permission to update credentials.\n",
exit(1);
default:
"%s: error talking to server, NIS+ error: %s.\n",
exit(1);
}
return (NULL);
}
/* Check whether this principal already has this type of credentials */
static nis_error
{
/* Don't want FOLLOW_PATH here */
switch (status) {
case NIS_NOTFOUND:
break;
case NIS_TRYAGAIN:
"%s: NIS+ server busy, try again later.\n",
exit(1);
case NIS_PERMISSION:
"%s: insufficient permission to look at credentials table\n",
exit(1);
case NIS_SUCCESS:
case NIS_S_SUCCESS:
break;
default:
"%s: error looking at cred table, NIS+ error: %s\n",
exit(1);
}
return (status);
}
/* Returns 0 if operation fails; 1 if successful. */
static
int
char *domain;
{
int status = 0;
case NIS_TRYAGAIN :
"%s: NIS+ server busy, try again later.\n",
exit(1);
case NIS_PERMISSION :
"%s: insufficient permission to update credentials.\n",
exit(1);
case NIS_SUCCESS :
status = 1;
break;
default:
"%s: error modifying credential, NIS+ error: %s.\n",
exit(1);
}
return (status);
}
static
int
char *domain;
{
int status = 0;
/* Assume check for cred_exists performed already */
case NIS_TRYAGAIN :
"%s: NIS+ server busy, try again later.\n",
exit(1);
case NIS_PERMISSION :
"%s: insufficient permission to update credentials.\n",
exit(1);
case NIS_SUCCESS :
status = 1;
break;
default:
"%s: error creating credential, NIS+ error: %s.\n",
exit(1);
}
return (status);
}
{
static nis_object obj;
return (&obj);
}
static char *attrFilter[] = {
"objectclass",
"nispublickey",
"nissecretkey",
(char *)NULL
};
/* Determines if there is a NisKeyObject objectclass in a given entry */
static int
{
char **fattrs;
return (1);
while (*fattrs) {
return (1);
fattrs++;
}
return (0);
}
static char *keyAttrs[] = {
"nispublickey",
"nissecretkey",
};
/*
* Replace or append new attribute value(s) to an attribute.
* Don't care about memory leaks, because program is short running.
*/
static int
char *mechname,
char *public,
char *crypt,
{
char **alist[2];
char *keys[2];
char *mechfilter;
int mechfilterlen;
int q = 0;
int i, j;
int keycount[] = {0, 0};
if (mechfilter == NULL)
return (0);
int found = 0;
for (i = 0; i < entry->attr_count; i++) {
int rep = 0;
int count = 0;
found++;
return (0);
for (j = 0; j < attr->value_count; j++) {
mechfilterlen) == 0) {
/* Replace entry */
rep++;
} else
++keycount[q];
}
if (!rep) {
/* Add entry to list */
sizeof (char *) * (count + 2));
return (0);
++keycount[q];
}
}
}
if (!found) {
/* Attribute does not exist, add entry anyways */
return (0);
++keycount[q];
}
}
sizeof (ns_ldap_attr_t))) == NULL)
return (0);
sizeof (ns_ldap_attr_t))) == NULL)
return (0);
return (1);
}
/*
* Do the actual Add or update of attributes in attrs.
* The parameter 'update4host' is a flag that tells the function which
* DN and password should be used to bind to ldap. If it is an update
* for a host (update4host > 0), the two parameters "bindDN" and
* "bindPasswd" would be used to bind as the directory manager,
* otherwise "dn" and "passwd" would be used to bind as an individual
* user.
*/
static void
update_ldap_attr(const char *dn,
const char *passwd,
int add,
int update4host,
const char *bindDN,
const char *bindPasswd)
{
int ldaprc;
int authstried = 0;
char *msg;
char *ldap_pw;
int status;
goto out;
}
/*
* if this is an update for host, use the bindDN from the
* command prompt, otherwise use user's DN directly.
*/
if (update4host)
else
goto out;
}
if (update4host) {
} else {
if (passwd)
else {
/* Make sure a valid password is received. */
if (status != PROMPTGET_SUCCESS) {
if (!ldap_pw)
goto out;
}
}
}
goto out;
}
/* get host certificate path, if one is configured */
goto out;
/* Load the service specific authentication method */
goto out;
/*
* if authpp is null, there is no serviceAuthenticationMethod
* try default authenticationMethod
*/
&errorp) != NS_LDAP_SUCCESS)
goto out;
}
/*
* if authpp is still null, then can not authenticate, log
* error message and return error
*/
" configured.\n");
goto out;
}
/*
* Walk the array and try all authentication methods in order except
* for "none".
*/
continue;
authstried++;
(const ns_ldap_attr_t * const *)attrs,
else
(const ns_ldap_attr_t * const *)attrs,
if (ldaprc == NS_LDAP_SUCCESS) {
/* clean up ns_cred_t structure in memory */
(void) __ns_ldap_freeCred(&credp);
return;
}
/* XXX add checking for cases of authentication errors */
if ((ldaprc == NS_LDAP_INTERNAL) &&
goto out;
}
}
if (authstried == 0)
out:
/* clean up ns_cred_t structure in memory */
(void) __ns_ldap_freeCred(&credp);
}
if (errorp) {
}
exit(1);
}
/*
* Update LDAP nisplublickey entry with new key information via SLDAP.
* Free and clean up memory that stores credential data soon after
* they are not used or an error comes up.
*/
int
ldap_update(char *mechname,
char *netname,
char *public,
char *crypt,
char *passwd)
{
char *netnamecpy;
char *id;
char *domain;
char *dn;
char *db;
char *filter;
int update4host = FALSE;
char *bindPasswd = NULL;
int status;
/* Generate DN */
return (0);
return (0);
else {
*domain++ = '\0';
*id++ = '\0';
return (0);
}
return (0);
}
}
/* We be user. */
exit(1);
}
db = "passwd";
if (filter)
else {
exit(1);
}
} else {
/* We be host. */
update4host = TRUE;
exit(1);
}
db = "hosts";
if (filter)
else {
exit(1);
}
/* Prompt for ldap bind DN for entry udpates */
if (status != PROMPTGET_SUCCESS) {
"Failed to get a valid LDAP bind DN.\n"
"%s: key-pair(s) unchanged.\n",
exit(1);
}
/* Prompt for ldap bind password */
if (status != PROMPTGET_SUCCESS) {
"Failed to get a valid LDAP bind password."
"\n%s: key-pair(s) unchanged.\n",
exit(1);
}
}
/* Construct attribute values */
exit(1);
}
exit(1);
}
/* Does entry exist? */
exit(1);
}
/* Entry exists, modify attributes for public and secret keys */
/* Is there a NisKeyObject in entry? */
/* Add NisKeyObject objectclass and the keys */
char **newattr;
/* set objectclass */
newattr[0] = "NisKeyObject";
sizeof (ns_ldap_attr_t))) == NULL) {
exit(1);
}
/* set publickey */
sizeof (ns_ldap_attr_t))) == NULL) {
exit(1);
}
/* set privatekey */
sizeof (ns_ldap_attr_t))) == NULL) {
exit(1);
}
/* terminator */
bindDN, bindPasswd);
} else {
/* object class already exists, replace keys */
"Could not generate LDAP attribute list.\n");
"%s: key-pair(s) unchanged.\n", program_name);
exit(1);
}
bindDN, bindPasswd);
}
return (0);
}
/* Returns 0 if successful; -1 if failure. (expected by setpublicmap). */
int
{
/*
* we take the domain given in the netname & the principal
* name if they match otherwise the local domain.
*/
if (! netdomain) {
return (0);
}
netdomain++; /* skip '@' */
/* make sure we don't run into buffer overflow */
return (0);
return (-1);
/* Now we have a key pair, build up the cred entry */
if (addition) {
/* owner: r, group: rmcd */
NIS_DESTROY_ACC)<<8);
} else {
}
}