view usr/src/cmd/rpcsvc/nis/utils/nisaddcred/makedescred.c @ 10008:b5d6e292a984

PSARC 2008/295 NISPASSWD_VERS2 6563443 nisaddcred and chkey have issues in md5 password encyption with passwords > eight characters
author Ashok Kumar T <Ashok.Kumar@Sun.COM>
date Wed, 01 Jul 2009 22:27:19 +0530
parents 68f95e015346
children
line wrap: on
line source

/*
 * 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
 */
/*
 *	makedescred.c
 *
 *	Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 *	Use is subject to license terms.
 */

/*
 * makedescred.c
 *
 * Make a "AUTH_DES" credential. This is the old secure rpc credentials from
 * SunOS 4.0 and Vanilla System V release 4.0.
 */


#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <shadow.h>
#include <string.h>
#include <ctype.h>
#include <nsswitch.h>
#include <netdb.h>
#include <rpcsvc/nis.h>
#include <rpcsvc/nispasswd.h>
#include <rpcsvc/nis_dhext.h>
#include <rpc/key_prot.h>
#include "nisaddcred.h"
#include <assert.h>

extern char *getpass();
extern char *crypt();
extern void __gen_dhkeys(char *, char *, char *);
extern int add_cred_obj(nis_object *, char *);
extern int  check_switch_policy(char *, char *, struct __nsw_switchconfig *,
				char *, char *);
extern nis_error cred_exists(char *, char *, char *);
extern char *get_password(uid_t, int, char *, char *);
extern int is_switch_policy(struct __nsw_switchconfig *, char *);
extern int key_setnet(struct key_netstarg *arg);
extern int make_dhext_cred(char *, char *, char *, char *);
extern int modify_cred_obj(nis_object *, char *);
extern int no_switch_policy(struct __nsw_switchconfig *);
extern int sanity_checks(char *, char *, char *, char *);
extern char *switch_policy_str(struct __nsw_switchconfig *);
extern void write_rootkey(char *, char *, keylen_t, algtype_t);
extern int xencrypt(char *, char *);

static const char *OPSYS = "unix";
#define	OPSYS_LEN 4

/* ************************ switch functions *************************** */

/*	NSW_NOTSUCCESS  NSW_NOTFOUND   NSW_UNAVAIL    NSW_TRYAGAIN */
#define	DEF_ACTION {__NSW_RETURN, __NSW_RETURN, __NSW_CONTINUE, __NSW_CONTINUE}


/* ***************************** keylogin stuff *************************** */
int
keylogin_des(char *netname, char *secret)
{
	struct key_netstarg netst;

	netst.st_pub_key[0] = 0;
	(void) memcpy(netst.st_priv_key, secret, HEXKEYBYTES);
	netst.st_netname = netname;

#ifdef NFS_AUTH
	nra.authtype = AUTH_DES;	/* only revoke DES creds */
	nra.uid = getuid();		/* use the real uid */
	if (_nfssys(NFS_REVAUTH, &nra) < 0) {
		perror("Warning: NFS credentials not destroyed");
		err = 1;
	}
#endif /* NFS_AUTH */


	/* 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");
		return (0);
	}

	return (1);
}


/*
 *	Definitions of the credential table.
 *
 * Column	Name			Contents
 * ------	----			--------
 *   0		cname			nis principal name
 *   1		auth_type		DES
 *   2		auth_name		netname
 *   3		public_auth_data	public key
 *   4		private_auth_data	encrypted secret key with checksum
 */

/*
 * Function for building DES credentials.
 *
 * The domain may be the local domain or some remote domain.
 * 'domain' should be the same as the domain found in netname,
 * which should be the home domain of nis+ principal.
 */


int
make_des_cred_be(char *nis_princ, char *netname, char *domain)
{
	nis_object	*obj = init_entry();
	char 		*pass;
	char		short_pass[DESCREDPASSLEN + 1];
	uid_t		uid;
	char 		public[HEXKEYBYTES + 1];
	char		secret[HEXKEYBYTES + 1];
	char		crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
	char		target_host[MAXHOSTNAMELEN+1];
	int		same_host = 0;
	int		status, len, addition;

	if (nis_princ == NULL)
		nis_princ = default_principal(domain);

	if (sanity_checks(nis_princ, netname, domain, "DES") == 0)
		return (0);

	addition = (cred_exists(nis_princ, "DES", domain) == NIS_NOTFOUND);

	/* Extract user/host information from netname */
	if (! isdigit(netname[OPSYS_LEN+1])) {
		uid = 0;  /* root */
		netname2host(netname, target_host, MAXHOSTNAMELEN);
		len = strlen(my_host)-1;   /* ignore trailing dot in my_host */
		if (len == strlen(target_host) &&
		    strncasecmp(target_host, my_host, len) == 0)
			same_host = 1;
	} else {
		uid = (uid_t)atoi(netname+OPSYS_LEN+1);
	}

	pass = get_password(uid, same_host, target_host, domain);
	if (pass == 0)
		return (0);

	(void) strlcpy(short_pass, pass, sizeof (short_pass));
	/* Get password with which to encrypt secret key. */
	(void) printf("%s key pair for %s (%s).\n",
	    addition? "Adding" : "Updating", netname, nis_princ);


	/* Encrypt secret key */
	(void) __gen_dhkeys(public, secret, short_pass);
	(void) memcpy(crypt1, secret, HEXKEYBYTES);
	(void) memcpy(crypt1 + HEXKEYBYTES, secret, KEYCHECKSUMSIZE);
	crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0;
	xencrypt(crypt1, short_pass);


	/* Now we have a key pair, build up the cred entry */
	ENTRY_VAL(obj, 0) = nis_princ;
	ENTRY_LEN(obj, 0) = strlen(nis_princ) + 1;

	ENTRY_VAL(obj, 1) = "DES";
	ENTRY_LEN(obj, 1) = 4;

	ENTRY_VAL(obj, 2) = netname;
	ENTRY_LEN(obj, 2) = strlen(netname) + 1;

	ENTRY_VAL(obj, 3) = public;
	ENTRY_LEN(obj, 3) = strlen(public) + 1;
#ifdef OLD_MODE
	strcat(ENTRY_VAL(obj, 3), ":");
	ENTRY_LEN(obj, 3)++;
#endif

	ENTRY_VAL(obj, 4) = crypt1;
	ENTRY_LEN(obj, 4) = strlen(crypt1) + 1;

	if (addition) {
		obj->zo_owner = nis_princ;
		obj->zo_group = my_group;
		obj->zo_domain = domain;
		/* owner: r, group: rmcd */
		obj->zo_access = ((NIS_READ_ACC<<16)|
		    (NIS_READ_ACC|NIS_MODIFY_ACC|NIS_CREATE_ACC|
		    NIS_DESTROY_ACC)<<8);
		status = add_cred_obj(obj, domain);
	} else {
		obj->EN_data.en_cols.en_cols_val[3].ec_flags |= EN_MODIFIED;
		obj->EN_data.en_cols.en_cols_val[4].ec_flags |= EN_MODIFIED;
		status = modify_cred_obj(obj, domain);
	}


	/* attempt keylogin if appropriate */
	if (status) {
		if ((uid == my_uid) && ((uid != 0) || same_host))
			keylogin_des(netname, secret);
		if ((uid == 0) && same_host)
			write_rootkey(secret, "des", 192, 0);
	}
	return (status);
}


int
make_des_cred(char *nis_princ, char *netname, char *domain, char *flavor)
{
	mechanism_t	**mechlist;
	int		status = 0;
	int		i = 0;

	if (mechlist = (mechanism_t **)__nis_get_mechanisms(FALSE)) {
		while (mechlist[i]) {
			status = make_dhext_cred(nis_princ, netname,
			    domain,
			    mechlist[i]->alias);
			if (!status)
				return (status);
			i++;
		}
	} else
		status = make_des_cred_be(nis_princ, netname, domain);

	return (status);
}


char *
get_des_cred(domain, flavor)
char *domain;
char *flavor;	/* Ignored. */
{
	int		uid, status;
	static char netname[MAXNETNAMELEN+1];

	uid = my_uid;

	if (uid == 0)
		status = host2netname(netname, (char *)NULL, domain);
	else {
		/* generate netname using uid and domain information. */
		int len;
		len = strlen(domain);
		if ((len + OPSYS_LEN + 3 + MAXIPRINT) > MAXNETNAMELEN) {
			printf("Domain name too long: \"%s\"\n", domain);
			goto not_found;
		}
		(void) sprintf(netname, "%s.%d@%s", OPSYS, uid, domain);
		len = strlen(netname);
		if (netname[len-1] == '.')
			netname[len-1] = '\0';

		status = 1;
	}

	if (status == 1) {
		printf("DES principal name : \"%s\"\n", netname);
		return (netname);
	}

not_found:
	printf("DES principal name for %d not found\n", uid);
	return (NULL);
}