xref: /onnv-gate/usr/src/lib/libc/port/gen/crypt.c (revision 11411:c2fe1bf96826)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
213864Sraf 
220Sstevel@tonic-gate /*
23*11411SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
276812Sraf #pragma	weak _crypt = crypt
286812Sraf #pragma weak _encrypt = encrypt
296812Sraf #pragma weak _setkey = setkey
300Sstevel@tonic-gate 
316812Sraf #include "lint.h"
320Sstevel@tonic-gate #include "mtlib.h"
330Sstevel@tonic-gate #include <synch.h>
340Sstevel@tonic-gate #include <thread.h>
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <dlfcn.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate #include <stdio.h>
390Sstevel@tonic-gate #include <strings.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <sys/time.h>
420Sstevel@tonic-gate #include <limits.h>
430Sstevel@tonic-gate #include <sys/types.h>
440Sstevel@tonic-gate #include <sys/stat.h>
450Sstevel@tonic-gate #include <fcntl.h>
460Sstevel@tonic-gate #include <syslog.h>
470Sstevel@tonic-gate #include <unistd.h>
483864Sraf #include <atomic.h>
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include <crypt.h>
510Sstevel@tonic-gate #include <libc.h>
520Sstevel@tonic-gate #include "tsd.h"
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #define	CRYPT_ALGORITHMS_ALLOW		"CRYPT_ALGORITHMS_ALLOW"
550Sstevel@tonic-gate #define	CRYPT_ALGORITHMS_DEPRECATE	"CRYPT_ALGORITHMS_DEPRECATE"
560Sstevel@tonic-gate #define	CRYPT_DEFAULT			"CRYPT_DEFAULT"
570Sstevel@tonic-gate #define	CRYPT_UNIX			"__unix__"
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #define	CRYPT_CONFFILE		"/etc/security/crypt.conf"
600Sstevel@tonic-gate #define	POLICY_CONF_FILE	"/etc/security/policy.conf"
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #define	CRYPT_CONFLINELENGTH	1024
630Sstevel@tonic-gate 
640Sstevel@tonic-gate #define	CRYPT_MODULE_ISA	"/$ISA/"
650Sstevel@tonic-gate #ifdef	_LP64
660Sstevel@tonic-gate #define	CRYPT_MODULE_DIR	"/usr/lib/security/64/"
670Sstevel@tonic-gate #define	CRYPT_ISA_DIR		"/64/"
680Sstevel@tonic-gate #else	/* !_LP64 */
690Sstevel@tonic-gate #define	CRYPT_MODULE_DIR	"/usr/lib/security/"
700Sstevel@tonic-gate #define	CRYPT_ISA_DIR		"/"
710Sstevel@tonic-gate #endif	/* _LP64 */
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * MAX_ALGNAME_LEN:
750Sstevel@tonic-gate  *
760Sstevel@tonic-gate  * In practical terms this is probably never any bigger than about 10, but...
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  * It has to fix the encrypted password filed of struct spwd it is
790Sstevel@tonic-gate  * theoretically the maximum length of the cipher minus the magic $ sign.
800Sstevel@tonic-gate  * Though that would be unexpected.
810Sstevel@tonic-gate  * Since it also has to fit in crypt.conf it is CRYPT_CONFLINELENGTH
820Sstevel@tonic-gate  * minus the path to the module and the minimum white space.
830Sstevel@tonic-gate  *
840Sstevel@tonic-gate  * CRYPT_MAXCIPHERTEXTLEN is defined in crypt.h and is smaller than
850Sstevel@tonic-gate  * CRYPT_CONFLINELENGTH, and probably always will be.
860Sstevel@tonic-gate  */
870Sstevel@tonic-gate #define	MAX_ALGNAME_LEN	(CRYPT_MAXCIPHERTEXTLEN - 1)
880Sstevel@tonic-gate 
890Sstevel@tonic-gate struct crypt_alg_s {
900Sstevel@tonic-gate 	void	*a_libhandle;
910Sstevel@tonic-gate 	char	*(*a_genhash)(char *, const size_t, const char *,
920Sstevel@tonic-gate 		    const char *, const char **);
930Sstevel@tonic-gate 	char	*(*a_gensalt)(char *, const size_t,
940Sstevel@tonic-gate 		    const char *, const struct passwd *, const char **);
950Sstevel@tonic-gate 	char	**a_params;
960Sstevel@tonic-gate 	int	a_nparams;
970Sstevel@tonic-gate };
980Sstevel@tonic-gate 
990Sstevel@tonic-gate struct crypt_policy_s {
1000Sstevel@tonic-gate 	char	*cp_default;
1010Sstevel@tonic-gate 	char	*cp_allow;
1020Sstevel@tonic-gate 	char	*cp_deny;
1030Sstevel@tonic-gate };
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate enum crypt_policy_error_e {
1060Sstevel@tonic-gate 	CPE_BOTH = 1,
1070Sstevel@tonic-gate 	CPE_MULTI
1080Sstevel@tonic-gate };
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static struct crypt_policy_s *getcryptpolicy(void);
1110Sstevel@tonic-gate static void free_crypt_policy(struct crypt_policy_s *policy);
1120Sstevel@tonic-gate static struct crypt_alg_s  *getalgbyname(const char *algname, boolean_t *found);
1130Sstevel@tonic-gate static void free_crypt_alg(struct crypt_alg_s *alg);
1140Sstevel@tonic-gate static char *getalgfromsalt(const char *salt);
1150Sstevel@tonic-gate static boolean_t alg_valid(const char *algname,
1160Sstevel@tonic-gate     const struct crypt_policy_s *policy);
1170Sstevel@tonic-gate static char *isa_path(const char *path);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate static char *_unix_crypt(const char *pw, const char *salt, char *iobuf);
1200Sstevel@tonic-gate static char *_unix_crypt_gensalt(char *gsbuffer, size_t gsbufflen,
1210Sstevel@tonic-gate 	    const char *oldpuresalt, const struct passwd *userinfo,
1220Sstevel@tonic-gate 	    const char *params[]);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate  * crypt - string encoding function
1270Sstevel@tonic-gate  *
1280Sstevel@tonic-gate  * This function encodes strings in a suitable for for secure storage
1290Sstevel@tonic-gate  * as passwords.  It generates the password hash given the plaintext and salt.
1300Sstevel@tonic-gate  *
1310Sstevel@tonic-gate  * If the first character of salt is "$" then we use crypt.conf(4) to
1320Sstevel@tonic-gate  * determine which plugin to use and run the crypt_genhash_impl(3c) function
1330Sstevel@tonic-gate  * from it.
1340Sstevel@tonic-gate  * Otherwise we use the old unix algorithm.
1350Sstevel@tonic-gate  *
1360Sstevel@tonic-gate  * RETURN VALUES
1370Sstevel@tonic-gate  *	On Success we return a pointer to the encoded string.  The
1380Sstevel@tonic-gate  *	return value points to thread specific static data and should NOT
1390Sstevel@tonic-gate  *	be passed free(3c).
1400Sstevel@tonic-gate  *	On failure we return NULL and set errno to one of:
1410Sstevel@tonic-gate  *		EINVAL, ELIBACC, ENOMEM, ENOSYS.
1420Sstevel@tonic-gate  */
1430Sstevel@tonic-gate char *
crypt(const char * plaintext,const char * salt)1440Sstevel@tonic-gate crypt(const char *plaintext, const char *salt)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate 	struct crypt_alg_s *alg;
1470Sstevel@tonic-gate 	char *ctbuffer;
1480Sstevel@tonic-gate 	char *ciphertext;
1490Sstevel@tonic-gate 	char *algname;
1500Sstevel@tonic-gate 	boolean_t found;
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	ctbuffer = tsdalloc(_T_CRYPT, CRYPT_MAXCIPHERTEXTLEN, NULL);
1530Sstevel@tonic-gate 	if (ctbuffer == NULL)
1540Sstevel@tonic-gate 		return (NULL);
1550Sstevel@tonic-gate 	bzero(ctbuffer, CRYPT_MAXCIPHERTEXTLEN);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	/*
1580Sstevel@tonic-gate 	 * '$' is never a possible salt char with the traditional unix
1590Sstevel@tonic-gate 	 * algorithm.  If the salt passed in is NULL or the first char
1600Sstevel@tonic-gate 	 * of the salt isn't a $ then do the traditional thing.
1610Sstevel@tonic-gate 	 * We also do the traditional thing if the salt is only 1 char.
1620Sstevel@tonic-gate 	 */
1630Sstevel@tonic-gate 	if (salt == NULL || salt[0] != '$' || strlen(salt) == 1) {
1640Sstevel@tonic-gate 		return (_unix_crypt(plaintext, salt, ctbuffer));
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	/*
1680Sstevel@tonic-gate 	 * Find the algorithm name from the salt and look it up in
1690Sstevel@tonic-gate 	 * crypt.conf(4) to find out what shared object to use.
1700Sstevel@tonic-gate 	 * If we can't find it in crypt.conf then getalgbyname would
1710Sstevel@tonic-gate 	 * have returned with found = B_FALSE so we use the unix algorithm.
1720Sstevel@tonic-gate 	 * If alg is NULL but found = B_TRUE then there is a problem with
1730Sstevel@tonic-gate 	 * the plugin so we fail leaving errno set to what getalgbyname()
1740Sstevel@tonic-gate 	 * set it to or EINVAL it if wasn't set.
1750Sstevel@tonic-gate 	 */
1760Sstevel@tonic-gate 	if ((algname = getalgfromsalt(salt)) == NULL) {
1770Sstevel@tonic-gate 		return (NULL);
1780Sstevel@tonic-gate 	}
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	errno = 0;
1810Sstevel@tonic-gate 	alg = getalgbyname(algname, &found);
1820Sstevel@tonic-gate 	if ((alg == NULL) || !found) {
1830Sstevel@tonic-gate 		if (errno == 0)
1840Sstevel@tonic-gate 			errno = EINVAL;
1850Sstevel@tonic-gate 		ciphertext = NULL;
1860Sstevel@tonic-gate 		goto cleanup;
1870Sstevel@tonic-gate 	} else if (!found) {
1880Sstevel@tonic-gate 		ciphertext = _unix_crypt(plaintext, salt, ctbuffer);
1890Sstevel@tonic-gate 	} else {
1900Sstevel@tonic-gate 		ciphertext = alg->a_genhash(ctbuffer, CRYPT_MAXCIPHERTEXTLEN,
1910Sstevel@tonic-gate 		    plaintext, salt, (const char **)alg->a_params);
1920Sstevel@tonic-gate 	}
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate cleanup:
1950Sstevel@tonic-gate 	free_crypt_alg(alg);
1960Sstevel@tonic-gate 	if (algname != NULL)
1970Sstevel@tonic-gate 		free(algname);
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	return (ciphertext);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * crypt_gensalt - generate salt string for string encoding
2040Sstevel@tonic-gate  *
2050Sstevel@tonic-gate  * This function generates the salt string pased to crypt(3c).
2060Sstevel@tonic-gate  * If oldsalt is NULL, the use the default algorithm.
2070Sstevel@tonic-gate  * Other wise check the policy in policy.conf to ensure that it is
2080Sstevel@tonic-gate  * either still allowed or not deprecated.
2090Sstevel@tonic-gate  *
2100Sstevel@tonic-gate  * RETURN VALUES
2110Sstevel@tonic-gate  * 	Return a pointer to the new salt, the caller is responsible
2120Sstevel@tonic-gate  * 	for using free(3c) on the return value.
2130Sstevel@tonic-gate  * 	Returns NULL on error and sets errno to one of:
2140Sstevel@tonic-gate  * 		EINVAL, ELIBACC, ENOMEM
2150Sstevel@tonic-gate  */
2160Sstevel@tonic-gate char *
crypt_gensalt(const char * oldsalt,const struct passwd * userinfo)2170Sstevel@tonic-gate crypt_gensalt(const char *oldsalt, const struct passwd *userinfo)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate 	struct crypt_alg_s *alg = NULL;
2200Sstevel@tonic-gate 	struct crypt_policy_s *policy = NULL;
2210Sstevel@tonic-gate 	char *newsalt = NULL;
2220Sstevel@tonic-gate 	char *gsbuffer;
2230Sstevel@tonic-gate 	char *algname = NULL;
2240Sstevel@tonic-gate 	boolean_t found;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	gsbuffer = calloc(CRYPT_MAXCIPHERTEXTLEN, sizeof (char *));
2270Sstevel@tonic-gate 	if (gsbuffer == NULL) {
2280Sstevel@tonic-gate 		errno = ENOMEM;
2290Sstevel@tonic-gate 		goto cleanup;
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	policy = getcryptpolicy();
2330Sstevel@tonic-gate 	if (policy == NULL) {
2340Sstevel@tonic-gate 		errno = EINVAL;
2350Sstevel@tonic-gate 		goto cleanup;
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	algname = getalgfromsalt(oldsalt);
2390Sstevel@tonic-gate 	if (!alg_valid(algname, policy)) {
2400Sstevel@tonic-gate 		free(algname);
2410Sstevel@tonic-gate 		algname = strdup(policy->cp_default);
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (strcmp(algname, CRYPT_UNIX) == 0) {
2450Sstevel@tonic-gate 		newsalt = _unix_crypt_gensalt(gsbuffer, CRYPT_MAXCIPHERTEXTLEN,
2460Sstevel@tonic-gate 		    oldsalt, userinfo, NULL);
2470Sstevel@tonic-gate 	} else {
2480Sstevel@tonic-gate 		errno = 0;
2490Sstevel@tonic-gate 		alg = getalgbyname(algname, &found);
2500Sstevel@tonic-gate 		if (alg == NULL || !found) {
2510Sstevel@tonic-gate 			if (errno == 0)
2520Sstevel@tonic-gate 				errno = EINVAL;
2530Sstevel@tonic-gate 			goto cleanup;
2540Sstevel@tonic-gate 		}
2550Sstevel@tonic-gate 		newsalt = alg->a_gensalt(gsbuffer, CRYPT_MAXCIPHERTEXTLEN,
2560Sstevel@tonic-gate 		    oldsalt, userinfo, (const char **)alg->a_params);
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate cleanup:
2600Sstevel@tonic-gate 	free_crypt_policy(policy);
2610Sstevel@tonic-gate 	free_crypt_alg(alg);
2620Sstevel@tonic-gate 	if (newsalt == NULL && gsbuffer != NULL)
2630Sstevel@tonic-gate 		free(gsbuffer);
2640Sstevel@tonic-gate 	if (algname != NULL)
2650Sstevel@tonic-gate 		free(algname);
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	return (newsalt);
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate /*
2710Sstevel@tonic-gate  * ===========================================================================
2720Sstevel@tonic-gate  * The remainder of this file contains internal interfaces for
2730Sstevel@tonic-gate  * the implementation of crypt(3c) and crypt_gensalt(3c)
2740Sstevel@tonic-gate  * ===========================================================================
2750Sstevel@tonic-gate  */
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate  * getalgfromsalt - extract the algorithm name from the salt string
2800Sstevel@tonic-gate  */
2810Sstevel@tonic-gate static char *
getalgfromsalt(const char * salt)2820Sstevel@tonic-gate getalgfromsalt(const char *salt)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	char algname[CRYPT_MAXCIPHERTEXTLEN];
2850Sstevel@tonic-gate 	int i;
2860Sstevel@tonic-gate 	int j;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	if (salt == NULL || strlen(salt) > CRYPT_MAXCIPHERTEXTLEN)
2890Sstevel@tonic-gate 		return (NULL);
2900Sstevel@tonic-gate 	/*
2910Sstevel@tonic-gate 	 * Salts are in this format:
2920Sstevel@tonic-gate 	 * $<algname>[,var=val,[var=val ...][$puresalt]$<ciphertext>
2930Sstevel@tonic-gate 	 *
2940Sstevel@tonic-gate 	 * The only bit we need to worry about here is extracting the
2950Sstevel@tonic-gate 	 * name which is the string between the first "$" and the first
2960Sstevel@tonic-gate 	 * of "," or second "$".
2970Sstevel@tonic-gate 	 */
2980Sstevel@tonic-gate 	if (salt[0] != '$') {
2990Sstevel@tonic-gate 		return (strdup(CRYPT_UNIX));
3000Sstevel@tonic-gate 	}
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	i = 1;
3030Sstevel@tonic-gate 	j = 0;
3040Sstevel@tonic-gate 	while (salt[i] != '\0' && salt[i] != '$' && salt[i] != ',') {
3050Sstevel@tonic-gate 		algname[j] = salt[i];
3060Sstevel@tonic-gate 		i++;
3070Sstevel@tonic-gate 		j++;
3080Sstevel@tonic-gate 	}
3090Sstevel@tonic-gate 	if (j == 0)
3100Sstevel@tonic-gate 		return (NULL);
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	algname[j] = '\0';
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	return (strdup(algname));
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate /*
3190Sstevel@tonic-gate  * log_invalid_policy - syslog helper
3200Sstevel@tonic-gate  */
3210Sstevel@tonic-gate static void
log_invalid_policy(enum crypt_policy_error_e error,char * value)3220Sstevel@tonic-gate log_invalid_policy(enum crypt_policy_error_e error, char *value)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	switch (error) {
3250Sstevel@tonic-gate 	case CPE_BOTH:
3260Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
3270Sstevel@tonic-gate 		    "crypt(3c): %s contains both %s and %s; only one may be "
3280Sstevel@tonic-gate 		    "specified, using first entry in file.", POLICY_CONF_FILE,
3290Sstevel@tonic-gate 		    CRYPT_ALGORITHMS_ALLOW, CRYPT_ALGORITHMS_DEPRECATE);
3300Sstevel@tonic-gate 		break;
3310Sstevel@tonic-gate 	case CPE_MULTI:
3320Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
3330Sstevel@tonic-gate 		    "crypt(3c): %s contains multiple %s entries;"
3340Sstevel@tonic-gate 		    "using first entry file.", POLICY_CONF_FILE, value);
3350Sstevel@tonic-gate 		break;
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate }
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate static char *
getval(const char * ival)3400Sstevel@tonic-gate getval(const char *ival)
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate 	char *tmp;
3430Sstevel@tonic-gate 	char *oval;
3440Sstevel@tonic-gate 	int off;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	if (ival == NULL)
3470Sstevel@tonic-gate 		return (NULL);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	if ((tmp = strchr(ival, '=')) == NULL)
3500Sstevel@tonic-gate 		return (NULL);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	oval = strdup(tmp + 1);	/* everything after the "=" */
3530Sstevel@tonic-gate 	if (oval == NULL)
3540Sstevel@tonic-gate 		return (NULL);
3550Sstevel@tonic-gate 	off = strlen(oval) - 1;
3560Sstevel@tonic-gate 	if (off < 0) {
3570Sstevel@tonic-gate 		free(oval);
3580Sstevel@tonic-gate 		return (NULL);
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 	if (oval[off] == '\n')
3610Sstevel@tonic-gate 		oval[off] = '\0';
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	return (oval);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate /*
3670Sstevel@tonic-gate  * getcryptpolicy - read /etc/security/policy.conf into a crypt_policy_s
3680Sstevel@tonic-gate  */
3690Sstevel@tonic-gate static struct crypt_policy_s *
getcryptpolicy(void)3700Sstevel@tonic-gate getcryptpolicy(void)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	FILE	*pconf;
3730Sstevel@tonic-gate 	char	line[BUFSIZ];
3740Sstevel@tonic-gate 	struct crypt_policy_s *policy;
3750Sstevel@tonic-gate 
3761914Scasper 	if ((pconf = fopen(POLICY_CONF_FILE, "rF")) == NULL) {
3770Sstevel@tonic-gate 		return (NULL);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	policy = malloc(sizeof (struct crypt_policy_s));
3810Sstevel@tonic-gate 	if (policy == NULL) {
3820Sstevel@tonic-gate 		return (NULL);
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 	policy->cp_default = NULL;
3850Sstevel@tonic-gate 	policy->cp_allow = NULL;
3860Sstevel@tonic-gate 	policy->cp_deny = NULL;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	while (!feof(pconf) &&
3890Sstevel@tonic-gate 	    (fgets(line, sizeof (line), pconf) != NULL)) {
3900Sstevel@tonic-gate 		if (strncasecmp(CRYPT_DEFAULT, line,
3910Sstevel@tonic-gate 		    strlen(CRYPT_DEFAULT)) == 0) {
3920Sstevel@tonic-gate 			if (policy->cp_default != NULL) {
3930Sstevel@tonic-gate 				log_invalid_policy(CPE_MULTI, CRYPT_DEFAULT);
3940Sstevel@tonic-gate 			} else {
3950Sstevel@tonic-gate 				policy->cp_default = getval(line);
3960Sstevel@tonic-gate 			}
3970Sstevel@tonic-gate 		}
3980Sstevel@tonic-gate 		if (strncasecmp(CRYPT_ALGORITHMS_ALLOW, line,
3990Sstevel@tonic-gate 		    strlen(CRYPT_ALGORITHMS_ALLOW)) == 0) {
4000Sstevel@tonic-gate 			if (policy->cp_deny != NULL) {
4010Sstevel@tonic-gate 				log_invalid_policy(CPE_BOTH, NULL);
4020Sstevel@tonic-gate 			} else if (policy->cp_allow != NULL) {
4030Sstevel@tonic-gate 				log_invalid_policy(CPE_MULTI,
4040Sstevel@tonic-gate 				    CRYPT_ALGORITHMS_ALLOW);
4050Sstevel@tonic-gate 			} else {
4060Sstevel@tonic-gate 				policy->cp_allow = getval(line);
4070Sstevel@tonic-gate 			}
4080Sstevel@tonic-gate 		}
4090Sstevel@tonic-gate 		if (strncasecmp(CRYPT_ALGORITHMS_DEPRECATE, line,
4100Sstevel@tonic-gate 		    strlen(CRYPT_ALGORITHMS_DEPRECATE)) == 0) {
4110Sstevel@tonic-gate 			if (policy->cp_allow != NULL) {
4120Sstevel@tonic-gate 				log_invalid_policy(CPE_BOTH, NULL);
4130Sstevel@tonic-gate 			} else if (policy->cp_deny != NULL) {
4140Sstevel@tonic-gate 				log_invalid_policy(CPE_MULTI,
4150Sstevel@tonic-gate 				    CRYPT_ALGORITHMS_DEPRECATE);
4160Sstevel@tonic-gate 			} else {
4170Sstevel@tonic-gate 				policy->cp_deny = getval(line);
4180Sstevel@tonic-gate 			}
4190Sstevel@tonic-gate 		}
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 	(void) fclose(pconf);
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	if (policy->cp_default == NULL) {
4240Sstevel@tonic-gate 		policy->cp_default = strdup(CRYPT_UNIX);
4250Sstevel@tonic-gate 		if (policy->cp_default == NULL)
4260Sstevel@tonic-gate 			free_crypt_policy(policy);
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	return (policy);
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate /*
4340Sstevel@tonic-gate  * alg_valid - is this algorithm valid given the policy ?
4350Sstevel@tonic-gate  */
4360Sstevel@tonic-gate static boolean_t
alg_valid(const char * algname,const struct crypt_policy_s * policy)4370Sstevel@tonic-gate alg_valid(const char *algname, const struct crypt_policy_s *policy)
4380Sstevel@tonic-gate {
4390Sstevel@tonic-gate 	char *lasts;
4400Sstevel@tonic-gate 	char *list;
4410Sstevel@tonic-gate 	char *entry;
4420Sstevel@tonic-gate 	boolean_t allowed = B_FALSE;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	if ((algname == NULL) || (policy == NULL)) {
4450Sstevel@tonic-gate 		return (B_FALSE);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	if (strcmp(algname, policy->cp_default) == 0) {
4490Sstevel@tonic-gate 		return (B_TRUE);
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	if (policy->cp_deny != NULL) {
4530Sstevel@tonic-gate 		list = policy->cp_deny;
4540Sstevel@tonic-gate 		allowed = B_FALSE;
4550Sstevel@tonic-gate 	} else if (policy->cp_allow != NULL) {
4560Sstevel@tonic-gate 		list = policy->cp_allow;
4570Sstevel@tonic-gate 		allowed = B_TRUE;
4580Sstevel@tonic-gate 	} else {
4590Sstevel@tonic-gate 		/*
4600Sstevel@tonic-gate 		 * Neither of allow or deny policies are set so anything goes.
4610Sstevel@tonic-gate 		 */
4620Sstevel@tonic-gate 		return (B_TRUE);
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 	lasts = list;
4650Sstevel@tonic-gate 	while ((entry = strtok_r(NULL, ",", &lasts)) != NULL) {
4660Sstevel@tonic-gate 		if (strcmp(entry, algname) == 0) {
4670Sstevel@tonic-gate 			return (allowed);
4680Sstevel@tonic-gate 		}
4690Sstevel@tonic-gate 	}
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	return (!allowed);
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate /*
4750Sstevel@tonic-gate  * getalgbyname - read crypt.conf(4) looking for algname
4760Sstevel@tonic-gate  *
4770Sstevel@tonic-gate  * RETURN VALUES
4780Sstevel@tonic-gate  *	On error NULL and errno is set
4790Sstevel@tonic-gate  *	On success the alg details including an open handle to the lib
4800Sstevel@tonic-gate  *	If crypt.conf(4) is okay but algname doesn't exist in it then
4810Sstevel@tonic-gate  *	return NULL the caller should then use the default algorithm
4820Sstevel@tonic-gate  *	as per the policy.
4830Sstevel@tonic-gate  */
4840Sstevel@tonic-gate static struct crypt_alg_s *
getalgbyname(const char * algname,boolean_t * found)4850Sstevel@tonic-gate getalgbyname(const char *algname, boolean_t *found)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate 	struct stat	stb;
4880Sstevel@tonic-gate 	int		configfd;
4890Sstevel@tonic-gate 	FILE		*fconf = NULL;
4900Sstevel@tonic-gate 	struct crypt_alg_s *alg = NULL;
4910Sstevel@tonic-gate 	char		line[CRYPT_CONFLINELENGTH];
4920Sstevel@tonic-gate 	int		linelen = 0;
4930Sstevel@tonic-gate 	int		lineno = 0;
4940Sstevel@tonic-gate 	char		*pathname = NULL;
4950Sstevel@tonic-gate 	char		*lasts = NULL;
4960Sstevel@tonic-gate 	char		*token = NULL;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	*found = B_FALSE;
4990Sstevel@tonic-gate 	if ((algname == NULL) || (strcmp(algname, CRYPT_UNIX) == 0)) {
5000Sstevel@tonic-gate 		return (NULL);
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	if ((configfd = open(CRYPT_CONFFILE, O_RDONLY)) == -1) {
5040Sstevel@tonic-gate 		syslog(LOG_ALERT, "crypt: open(%s) failed: %s",
5056812Sraf 		    CRYPT_CONFFILE, strerror(errno));
5060Sstevel@tonic-gate 		return (NULL);
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	/*
5100Sstevel@tonic-gate 	 * Stat the file so we can check modes and ownerships
5110Sstevel@tonic-gate 	 */
5120Sstevel@tonic-gate 	if (fstat(configfd, &stb) < 0) {
5130Sstevel@tonic-gate 		syslog(LOG_ALERT, "crypt: stat(%s) failed: %s",
5146812Sraf 		    CRYPT_CONFFILE, strerror(errno));
5150Sstevel@tonic-gate 		goto cleanup;
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	/*
5190Sstevel@tonic-gate 	 * Check the ownership of the file
5200Sstevel@tonic-gate 	 */
5210Sstevel@tonic-gate 	if (stb.st_uid != (uid_t)0) {
5220Sstevel@tonic-gate 		syslog(LOG_ALERT,
5230Sstevel@tonic-gate 		    "crypt: Owner of %s is not root", CRYPT_CONFFILE);
5240Sstevel@tonic-gate 		goto cleanup;
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	/*
5280Sstevel@tonic-gate 	 * Check the modes on the file
5290Sstevel@tonic-gate 	 */
5300Sstevel@tonic-gate 	if (stb.st_mode & S_IWGRP) {
5310Sstevel@tonic-gate 		syslog(LOG_ALERT,
5320Sstevel@tonic-gate 		    "crypt: %s writable by group", CRYPT_CONFFILE);
5330Sstevel@tonic-gate 		goto cleanup;
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 	if (stb.st_mode & S_IWOTH) {
5360Sstevel@tonic-gate 		syslog(LOG_ALERT,
5376812Sraf 		    "crypt: %s writable by world", CRYPT_CONFFILE);
5380Sstevel@tonic-gate 		goto cleanup;
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate 
5411914Scasper 	if ((fconf = fdopen(configfd, "rF")) == NULL) {
5420Sstevel@tonic-gate 		syslog(LOG_ALERT, "crypt: fdopen(%d) failed: %s",
5436812Sraf 		    configfd, strerror(errno));
5440Sstevel@tonic-gate 		goto cleanup;
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	/*
5480Sstevel@tonic-gate 	 * /etc/security/crypt.conf has 3 fields:
5490Sstevel@tonic-gate 	 * <algname>	<pathname>	[<name[=val]>[<name[=val]>]]
5500Sstevel@tonic-gate 	 */
5510Sstevel@tonic-gate 	errno = 0;
5520Sstevel@tonic-gate 	while (!(*found) &&
5530Sstevel@tonic-gate 	    ((fgets(line, sizeof (line), fconf) != NULL) && !feof(fconf))) {
5540Sstevel@tonic-gate 		lineno++;
5550Sstevel@tonic-gate 		/*
5560Sstevel@tonic-gate 		 * Skip over comments
5570Sstevel@tonic-gate 		 */
5580Sstevel@tonic-gate 		if ((line[0] == '#') || (line[0] == '\n')) {
5590Sstevel@tonic-gate 			continue;
5600Sstevel@tonic-gate 		}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 		linelen = strlen(line);
5630Sstevel@tonic-gate 		line[--linelen] = '\0';	/* chop the trailing \n */
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 		token = strtok_r(line, " \t", &lasts);
5660Sstevel@tonic-gate 		if (token == NULL) {
5670Sstevel@tonic-gate 			continue;
5680Sstevel@tonic-gate 		}
5690Sstevel@tonic-gate 		if (strcmp(token, algname) == 0) {
5700Sstevel@tonic-gate 			*found = B_TRUE;
5710Sstevel@tonic-gate 		}
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 	if (!found) {
5740Sstevel@tonic-gate 		errno = EINVAL;
5750Sstevel@tonic-gate 		goto cleanup;
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	token = strtok_r(NULL, " \t", &lasts);
5790Sstevel@tonic-gate 	if (token == NULL) {
5800Sstevel@tonic-gate 		/*
5810Sstevel@tonic-gate 		 * Broken config file
5820Sstevel@tonic-gate 		 */
5830Sstevel@tonic-gate 		syslog(LOG_ALERT, "crypt(3c): %s may be corrupt at line %d",
5840Sstevel@tonic-gate 		    CRYPT_CONFFILE, lineno);
5850Sstevel@tonic-gate 		*found = B_FALSE;
5860Sstevel@tonic-gate 		errno = EINVAL;
5870Sstevel@tonic-gate 		goto cleanup;
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	if ((pathname = isa_path(token)) == NULL) {
5910Sstevel@tonic-gate 		if (errno != ENOMEM)
5920Sstevel@tonic-gate 			errno = EINVAL;
5930Sstevel@tonic-gate 		*found = B_FALSE;
5940Sstevel@tonic-gate 		goto cleanup;
5950Sstevel@tonic-gate 	}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	if ((alg = malloc(sizeof (struct crypt_alg_s))) == NULL) {
5980Sstevel@tonic-gate 		*found = B_FALSE;
5990Sstevel@tonic-gate 		goto cleanup;
6000Sstevel@tonic-gate 	}
6010Sstevel@tonic-gate 	alg->a_libhandle = NULL;
6020Sstevel@tonic-gate 	alg->a_genhash = NULL;
6030Sstevel@tonic-gate 	alg->a_gensalt = NULL;
6040Sstevel@tonic-gate 	alg->a_params = NULL;
6050Sstevel@tonic-gate 	alg->a_nparams = 0;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	/*
6080Sstevel@tonic-gate 	 * The rest of the line is module specific params, space
6090Sstevel@tonic-gate 	 * seprated. We wait until after we have checked the module is
6100Sstevel@tonic-gate 	 * valid before parsing them into a_params, this saves us
6110Sstevel@tonic-gate 	 * having to free them later if there is a problem.
6120Sstevel@tonic-gate 	 */
6130Sstevel@tonic-gate 	if ((alg->a_libhandle = dlopen(pathname, RTLD_NOW)) == NULL) {
6140Sstevel@tonic-gate 		syslog(LOG_ERR, "crypt(3c) unable to dlopen %s: %s",
6150Sstevel@tonic-gate 		    pathname, dlerror());
6160Sstevel@tonic-gate 		errno = ELIBACC;
6170Sstevel@tonic-gate 		*found = B_FALSE;
6180Sstevel@tonic-gate 		goto cleanup;
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	alg->a_genhash =
6220Sstevel@tonic-gate 	    (char *(*)())dlsym(alg->a_libhandle, "crypt_genhash_impl");
6230Sstevel@tonic-gate 	if (alg->a_genhash == NULL) {
6240Sstevel@tonic-gate 		syslog(LOG_ERR, "crypt(3c) unable to find cryp_genhash_impl"
6250Sstevel@tonic-gate 		    "symbol in %s: %s", pathname, dlerror());
6260Sstevel@tonic-gate 		errno = ELIBACC;
6270Sstevel@tonic-gate 		*found = B_FALSE;
6280Sstevel@tonic-gate 		goto cleanup;
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 	alg->a_gensalt =
6310Sstevel@tonic-gate 	    (char *(*)())dlsym(alg->a_libhandle, "crypt_gensalt_impl");
6320Sstevel@tonic-gate 	if (alg->a_gensalt == NULL) {
6330Sstevel@tonic-gate 		syslog(LOG_ERR, "crypt(3c) unable to find crypt_gensalt_impl"
6340Sstevel@tonic-gate 		    "symbol in %s: %s", pathname, dlerror());
6350Sstevel@tonic-gate 		errno = ELIBACC;
6360Sstevel@tonic-gate 		*found = B_FALSE;
6370Sstevel@tonic-gate 		goto cleanup;
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	/*
6410Sstevel@tonic-gate 	 * We have a good module so build the a_params if we have any.
6420Sstevel@tonic-gate 	 * Count how much space we need first and then allocate an array
6430Sstevel@tonic-gate 	 * to hold that many module params.
6440Sstevel@tonic-gate 	 */
6450Sstevel@tonic-gate 	if (lasts != NULL) {
6460Sstevel@tonic-gate 		int nparams = 0;
6470Sstevel@tonic-gate 		char *tparams;
6480Sstevel@tonic-gate 		char *tplasts;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		if ((tparams = strdup(lasts)) == NULL) {
6510Sstevel@tonic-gate 			*found = B_FALSE;
6520Sstevel@tonic-gate 			goto cleanup;
6530Sstevel@tonic-gate 		}
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		(void) strtok_r(tparams, " \t", &tplasts);
6560Sstevel@tonic-gate 		do {
6570Sstevel@tonic-gate 			nparams++;
6580Sstevel@tonic-gate 		} while (strtok_r(NULL, " \t", &tplasts) != NULL);
6590Sstevel@tonic-gate 		free(tparams);
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 		alg->a_params = calloc(nparams + 1, sizeof (char *));
6620Sstevel@tonic-gate 		if (alg->a_params == NULL) {
6630Sstevel@tonic-gate 			*found = B_FALSE;
6640Sstevel@tonic-gate 			goto cleanup;
6650Sstevel@tonic-gate 		}
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 		while ((token = strtok_r(NULL, " \t", &lasts)) != NULL) {
6680Sstevel@tonic-gate 			alg->a_params[alg->a_nparams++] = token;
6690Sstevel@tonic-gate 		}
6700Sstevel@tonic-gate 	}
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate cleanup:
6730Sstevel@tonic-gate 	if (*found == B_FALSE) {
6740Sstevel@tonic-gate 		free_crypt_alg(alg);
6750Sstevel@tonic-gate 		alg = NULL;
6760Sstevel@tonic-gate 	}
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	if (pathname != NULL) {
6790Sstevel@tonic-gate 		free(pathname);
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	if (fconf != NULL) {
6830Sstevel@tonic-gate 		(void) fclose(fconf);
6840Sstevel@tonic-gate 	} else {
6850Sstevel@tonic-gate 		(void) close(configfd);
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	return (alg);
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate static void
free_crypt_alg(struct crypt_alg_s * alg)6920Sstevel@tonic-gate free_crypt_alg(struct crypt_alg_s *alg)
6930Sstevel@tonic-gate {
6940Sstevel@tonic-gate 	if (alg == NULL)
6950Sstevel@tonic-gate 		return;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	if (alg->a_libhandle != NULL) {
6980Sstevel@tonic-gate 		(void) dlclose(alg->a_libhandle);
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 	if (alg->a_nparams != NULL) {
7010Sstevel@tonic-gate 		free(alg->a_params);
7020Sstevel@tonic-gate 	}
7030Sstevel@tonic-gate 	free(alg);
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate static void
free_crypt_policy(struct crypt_policy_s * policy)7070Sstevel@tonic-gate free_crypt_policy(struct crypt_policy_s *policy)
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate 	if (policy == NULL)
7100Sstevel@tonic-gate 		return;
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	if (policy->cp_default != NULL) {
7130Sstevel@tonic-gate 		bzero(policy->cp_default, strlen(policy->cp_default));
7140Sstevel@tonic-gate 		free(policy->cp_default);
7150Sstevel@tonic-gate 		policy->cp_default = NULL;
7160Sstevel@tonic-gate 	}
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	if (policy->cp_allow != NULL) {
7190Sstevel@tonic-gate 		bzero(policy->cp_allow, strlen(policy->cp_allow));
7200Sstevel@tonic-gate 		free(policy->cp_allow);
7210Sstevel@tonic-gate 		policy->cp_allow = NULL;
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	if (policy->cp_deny != NULL) {
7250Sstevel@tonic-gate 		bzero(policy->cp_deny, strlen(policy->cp_deny));
7260Sstevel@tonic-gate 		free(policy->cp_deny);
7270Sstevel@tonic-gate 		policy->cp_deny = NULL;
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	free(policy);
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate /*
7350Sstevel@tonic-gate  * isa_path - prepend the default dir or patch up the $ISA in path
7360Sstevel@tonic-gate  * 	Caller is responsible for calling free(3c) on the result.
7370Sstevel@tonic-gate  */
7380Sstevel@tonic-gate static char *
isa_path(const char * path)7390Sstevel@tonic-gate isa_path(const char *path)
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate 	char *ret = NULL;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	if ((path == NULL) || (strlen(path) > PATH_MAX)) {
7440Sstevel@tonic-gate 		return (NULL);
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	ret = calloc(PATH_MAX, sizeof (char));
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	/*
7500Sstevel@tonic-gate 	 * Module path doesn't start with "/" then prepend
7510Sstevel@tonic-gate 	 * the default search path CRYPT_MODULE_DIR (/usr/lib/security/$ISA)
7520Sstevel@tonic-gate 	 */
7530Sstevel@tonic-gate 	if (path[0] != '/') {
7540Sstevel@tonic-gate 		if (snprintf(ret, PATH_MAX, "%s%s", CRYPT_MODULE_DIR,
7550Sstevel@tonic-gate 		    path) > PATH_MAX) {
7560Sstevel@tonic-gate 			free(ret);
7570Sstevel@tonic-gate 			return (NULL);
7580Sstevel@tonic-gate 		}
7590Sstevel@tonic-gate 	} else { /* patch up $ISA */
7600Sstevel@tonic-gate 		char *isa;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		if ((isa = strstr(path, CRYPT_MODULE_ISA)) != NULL) {
7630Sstevel@tonic-gate 			*isa = '\0';
7640Sstevel@tonic-gate 			isa += strlen(CRYPT_MODULE_ISA);
7650Sstevel@tonic-gate 			if (snprintf(ret, PATH_MAX, "%s%s%s", path,
7660Sstevel@tonic-gate 			    CRYPT_ISA_DIR, isa) > PATH_MAX) {
7670Sstevel@tonic-gate 				free(ret);
7680Sstevel@tonic-gate 				return (NULL);
7690Sstevel@tonic-gate 			}
7700Sstevel@tonic-gate 		} else {
7710Sstevel@tonic-gate 			free(ret);
7720Sstevel@tonic-gate 			ret = strdup(path);
7730Sstevel@tonic-gate 		}
7740Sstevel@tonic-gate 	}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	return (ret);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate /*ARGSUSED*/
7810Sstevel@tonic-gate static char *
_unix_crypt_gensalt(char * gsbuffer,size_t gsbufflen,const char * oldpuresalt,const struct passwd * userinfo,const char * argv[])7820Sstevel@tonic-gate _unix_crypt_gensalt(char *gsbuffer,
7830Sstevel@tonic-gate 	    size_t gsbufflen,
7840Sstevel@tonic-gate 	    const char *oldpuresalt,
7850Sstevel@tonic-gate 	    const struct passwd *userinfo,
7860Sstevel@tonic-gate 	    const char *argv[])
7870Sstevel@tonic-gate {
7880Sstevel@tonic-gate 	static const char saltchars[] =
7890Sstevel@tonic-gate 	    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
7900Sstevel@tonic-gate 	struct timeval tv;
7910Sstevel@tonic-gate 
792*11411SSurya.Prakki@Sun.COM 	(void) gettimeofday(&tv, (void *) 0);
7930Sstevel@tonic-gate 	srand48(tv.tv_sec ^ tv.tv_usec);
7940Sstevel@tonic-gate 	gsbuffer[0] = saltchars[lrand48() % 64]; /* lrand48() is MT-SAFE */
7950Sstevel@tonic-gate 	gsbuffer[1] = saltchars[lrand48() % 64]; /* lrand48() is MT-SAFE */
7960Sstevel@tonic-gate 	gsbuffer[2] = '\0';
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	return (gsbuffer);
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate /*
8020Sstevel@tonic-gate  * The rest of the code below comes from the old crypt.c and is the
8030Sstevel@tonic-gate  * implementation of the hardwired/fallback traditional algorithm
8040Sstevel@tonic-gate  * It has been otimized to take better advantage of MT features.
8050Sstevel@tonic-gate  *
8060Sstevel@tonic-gate  * It is included here to reduce the overhead of dlopen()
8070Sstevel@tonic-gate  * for the common case.
8080Sstevel@tonic-gate  */
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
8120Sstevel@tonic-gate /*	  All Rights Reserved  	*/
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate /*
8170Sstevel@tonic-gate  * This program implements a data encryption algorithm to encrypt passwords.
8180Sstevel@tonic-gate  */
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate static mutex_t crypt_lock = DEFAULTMUTEX;
8210Sstevel@tonic-gate #define	TSDBUFSZ	(66 + 16)
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate static const char IP[] = {
8240Sstevel@tonic-gate 	58, 50, 42, 34, 26, 18, 10, 2,
8250Sstevel@tonic-gate 	60, 52, 44, 36, 28, 20, 12, 4,
8260Sstevel@tonic-gate 	62, 54, 46, 38, 30, 22, 14, 6,
8270Sstevel@tonic-gate 	64, 56, 48, 40, 32, 24, 16, 8,
8280Sstevel@tonic-gate 	57, 49, 41, 33, 25, 17, 9, 1,
8290Sstevel@tonic-gate 	59, 51, 43, 35, 27, 19, 11, 3,
8300Sstevel@tonic-gate 	61, 53, 45, 37, 29, 21, 13, 5,
8310Sstevel@tonic-gate 	63, 55, 47, 39, 31, 23, 15, 7,
8320Sstevel@tonic-gate };
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate static const char FP[] = {
8350Sstevel@tonic-gate 	40, 8, 48, 16, 56, 24, 64, 32,
8360Sstevel@tonic-gate 	39, 7, 47, 15,  55, 23, 63, 31,
8370Sstevel@tonic-gate 	38, 6, 46, 14, 54, 22, 62, 30,
8380Sstevel@tonic-gate 	37, 5, 45, 13, 53, 21, 61, 29,
8390Sstevel@tonic-gate 	36, 4, 44, 12, 52, 20, 60, 28,
8400Sstevel@tonic-gate 	35, 3, 43, 11, 51, 19, 59, 27,
8410Sstevel@tonic-gate 	34, 2, 42, 10, 50, 18, 58, 26,
8420Sstevel@tonic-gate 	33, 1, 41, 9, 49, 17, 57, 25,
8430Sstevel@tonic-gate };
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate static const char PC1_C[] = {
8460Sstevel@tonic-gate 	57, 49, 41, 33, 25, 17, 9,
8470Sstevel@tonic-gate 	1, 58, 50, 42, 34, 26, 18,
8480Sstevel@tonic-gate 	10, 2, 59, 51, 43, 35, 27,
8490Sstevel@tonic-gate 	19, 11, 3, 60, 52, 44, 36,
8500Sstevel@tonic-gate };
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate static const char PC1_D[] = {
8530Sstevel@tonic-gate 	63, 55, 47, 39, 31, 23, 15,
8540Sstevel@tonic-gate 	7, 62, 54, 46, 38, 30, 22,
8550Sstevel@tonic-gate 	14, 6, 61, 53, 45, 37, 29,
8560Sstevel@tonic-gate 	21, 13, 5, 28, 20, 12, 4,
8570Sstevel@tonic-gate };
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate static const char shifts[] = {
8600Sstevel@tonic-gate 	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
8610Sstevel@tonic-gate };
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate static const char PC2_C[] = {
8640Sstevel@tonic-gate 	14, 17, 11, 24, 1, 5,
8650Sstevel@tonic-gate 	3, 28, 15, 6, 21, 10,
8660Sstevel@tonic-gate 	23, 19, 12, 4, 26, 8,
8670Sstevel@tonic-gate 	16, 7, 27, 20, 13, 2,
8680Sstevel@tonic-gate };
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate static const char PC2_D[] = {
8710Sstevel@tonic-gate 	41, 52, 31, 37, 47, 55,
8720Sstevel@tonic-gate 	30, 40, 51, 45, 33, 48,
8730Sstevel@tonic-gate 	44, 49, 39, 56, 34, 53,
8740Sstevel@tonic-gate 	46, 42, 50, 36, 29, 32,
8750Sstevel@tonic-gate };
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate static char C[28];
8780Sstevel@tonic-gate static char D[28];
8790Sstevel@tonic-gate static char *KS;
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate static char E[48];
8820Sstevel@tonic-gate static const char e2[] = {
8830Sstevel@tonic-gate 	32, 1, 2, 3, 4, 5,
8840Sstevel@tonic-gate 	4, 5, 6, 7, 8, 9,
8850Sstevel@tonic-gate 	8, 9, 10, 11, 12, 13,
8860Sstevel@tonic-gate 	12, 13, 14, 15, 16, 17,
8870Sstevel@tonic-gate 	16, 17, 18, 19, 20, 21,
8880Sstevel@tonic-gate 	20, 21, 22, 23, 24, 25,
8890Sstevel@tonic-gate 	24, 25, 26, 27, 28, 29,
8900Sstevel@tonic-gate 	28, 29, 30, 31, 32, 1,
8910Sstevel@tonic-gate };
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate /*
8940Sstevel@tonic-gate  * The KS array (768 bytes) is allocated once, and only if
8950Sstevel@tonic-gate  * one of _unix_crypt(), encrypt() or setkey() is called.
8960Sstevel@tonic-gate  * The complexity below is due to the fact that calloc()
8970Sstevel@tonic-gate  * must not be called while holding any locks.
8980Sstevel@tonic-gate  */
8990Sstevel@tonic-gate static int
allocate_KS(void)9000Sstevel@tonic-gate allocate_KS(void)
9010Sstevel@tonic-gate {
9020Sstevel@tonic-gate 	char *ks;
9030Sstevel@tonic-gate 	int failed;
9040Sstevel@tonic-gate 	int assigned;
9050Sstevel@tonic-gate 
9063864Sraf 	if (KS != NULL) {		/* already allocated */
9073864Sraf 		membar_consumer();
9080Sstevel@tonic-gate 		return (0);
9093864Sraf 	}
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	ks = calloc(16, 48 * sizeof (char));
9120Sstevel@tonic-gate 	failed = 0;
9130Sstevel@tonic-gate 	lmutex_lock(&crypt_lock);
9140Sstevel@tonic-gate 	if (KS != NULL) {	/* someone else got here first */
9150Sstevel@tonic-gate 		assigned = 0;
9160Sstevel@tonic-gate 	} else {
9170Sstevel@tonic-gate 		assigned = 1;
9183864Sraf 		membar_producer();
9190Sstevel@tonic-gate 		if ((KS = ks) == NULL)	/* calloc() failed */
9200Sstevel@tonic-gate 			failed = 1;
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate 	lmutex_unlock(&crypt_lock);
9230Sstevel@tonic-gate 	if (!assigned)
9240Sstevel@tonic-gate 		free(ks);
9250Sstevel@tonic-gate 	return (failed);
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate static void
unlocked_setkey(const char * key)9290Sstevel@tonic-gate unlocked_setkey(const char *key)
9300Sstevel@tonic-gate {
9310Sstevel@tonic-gate 	int i, j, k;
9320Sstevel@tonic-gate 	char t;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	for (i = 0; i < 28; i++) {
9350Sstevel@tonic-gate 		C[i] = key[PC1_C[i]-1];
9360Sstevel@tonic-gate 		D[i] = key[PC1_D[i]-1];
9370Sstevel@tonic-gate 	}
9380Sstevel@tonic-gate 	for (i = 0; i < 16; i++) {
9390Sstevel@tonic-gate 		for (k = 0; k < shifts[i]; k++) {
9400Sstevel@tonic-gate 			t = C[0];
9410Sstevel@tonic-gate 			for (j = 0; j < 28-1; j++)
9420Sstevel@tonic-gate 				C[j] = C[j+1];
9430Sstevel@tonic-gate 			C[27] = t;
9440Sstevel@tonic-gate 			t = D[0];
9450Sstevel@tonic-gate 			for (j = 0; j < 28-1; j++)
9460Sstevel@tonic-gate 				D[j] = D[j+1];
9470Sstevel@tonic-gate 			D[27] = t;
9480Sstevel@tonic-gate 		}
9490Sstevel@tonic-gate 		for (j = 0; j < 24; j++) {
9500Sstevel@tonic-gate 			int index = i * 48;
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 			*(KS+index+j) = C[PC2_C[j]-1];
9530Sstevel@tonic-gate 			*(KS+index+j+24) = D[PC2_D[j]-28-1];
9540Sstevel@tonic-gate 		}
9550Sstevel@tonic-gate 	}
9560Sstevel@tonic-gate 	for (i = 0; i < 48; i++)
9570Sstevel@tonic-gate 		E[i] = e2[i];
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate static const char S[8][64] = {
9610Sstevel@tonic-gate 	14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
9620Sstevel@tonic-gate 	0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
9630Sstevel@tonic-gate 	4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
9640Sstevel@tonic-gate 	15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
9670Sstevel@tonic-gate 	3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
9680Sstevel@tonic-gate 	0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
9690Sstevel@tonic-gate 	13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
9720Sstevel@tonic-gate 	13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
9730Sstevel@tonic-gate 	13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
9740Sstevel@tonic-gate 	1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
9770Sstevel@tonic-gate 	13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
9780Sstevel@tonic-gate 	10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
9790Sstevel@tonic-gate 	3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
9820Sstevel@tonic-gate 	14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
9830Sstevel@tonic-gate 	4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
9840Sstevel@tonic-gate 	11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
9870Sstevel@tonic-gate 	10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9880Sstevel@tonic-gate 	9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
9890Sstevel@tonic-gate 	4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
9920Sstevel@tonic-gate 	13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
9930Sstevel@tonic-gate 	1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
9940Sstevel@tonic-gate 	6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
9970Sstevel@tonic-gate 	1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
9980Sstevel@tonic-gate 	7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
9990Sstevel@tonic-gate 	2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11,
10000Sstevel@tonic-gate };
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate static const char P[] = {
10030Sstevel@tonic-gate 	16, 7, 20, 21,
10040Sstevel@tonic-gate 	29, 12, 28, 17,
10050Sstevel@tonic-gate 	1, 15, 23, 26,
10060Sstevel@tonic-gate 	5, 18, 31, 10,
10070Sstevel@tonic-gate 	2, 8, 24, 14,
10080Sstevel@tonic-gate 	32, 27, 3, 9,
10090Sstevel@tonic-gate 	19, 13, 30, 6,
10100Sstevel@tonic-gate 	22, 11, 4, 25,
10110Sstevel@tonic-gate };
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate static char L[64];
10140Sstevel@tonic-gate static char tempL[32];
10150Sstevel@tonic-gate static char f[32];
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate static char preS[48];
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate /*ARGSUSED*/
10200Sstevel@tonic-gate static void
unlocked_encrypt(char * block,int fake)10210Sstevel@tonic-gate unlocked_encrypt(char *block, int fake)
10220Sstevel@tonic-gate {
10230Sstevel@tonic-gate 	int	i;
10240Sstevel@tonic-gate 	int t, j, k;
10250Sstevel@tonic-gate 	char *R = &L[32];
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	for (j = 0; j < 64; j++)
10280Sstevel@tonic-gate 		L[j] = block[IP[j]-1];
10290Sstevel@tonic-gate 	for (i = 0; i < 16; i++) {
10300Sstevel@tonic-gate 		int index = i * 48;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 		for (j = 0; j < 32; j++)
10330Sstevel@tonic-gate 			tempL[j] = R[j];
10340Sstevel@tonic-gate 		for (j = 0; j < 48; j++)
10350Sstevel@tonic-gate 			preS[j] = R[E[j]-1] ^ *(KS+index+j);
10360Sstevel@tonic-gate 		for (j = 0; j < 8; j++) {
10370Sstevel@tonic-gate 			t = 6 * j;
10386812Sraf 			k = S[j][(preS[t+0]<<5) +
10396812Sraf 			    (preS[t+1]<<3) +
10406812Sraf 			    (preS[t+2]<<2) +
10416812Sraf 			    (preS[t+3]<<1) +
10426812Sraf 			    (preS[t+4]<<0) +
10436812Sraf 			    (preS[t+5]<<4)];
10440Sstevel@tonic-gate 			t = 4*j;
10450Sstevel@tonic-gate 			f[t+0] = (k>>3)&01;
10460Sstevel@tonic-gate 			f[t+1] = (k>>2)&01;
10470Sstevel@tonic-gate 			f[t+2] = (k>>1)&01;
10480Sstevel@tonic-gate 			f[t+3] = (k>>0)&01;
10490Sstevel@tonic-gate 		}
10500Sstevel@tonic-gate 		for (j = 0; j < 32; j++)
10510Sstevel@tonic-gate 			R[j] = L[j] ^ f[P[j]-1];
10520Sstevel@tonic-gate 		for (j = 0; j < 32; j++)
10530Sstevel@tonic-gate 			L[j] = tempL[j];
10540Sstevel@tonic-gate 	}
10550Sstevel@tonic-gate 	for (j = 0; j < 32; j++) {
10560Sstevel@tonic-gate 		t = L[j];
10570Sstevel@tonic-gate 		L[j] = R[j];
10580Sstevel@tonic-gate 		R[j] = (char)t;
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 	for (j = 0; j < 64; j++)
10610Sstevel@tonic-gate 		block[j] = L[FP[j]-1];
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate char *
_unix_crypt(const char * pw,const char * salt,char * iobuf)10650Sstevel@tonic-gate _unix_crypt(const char *pw, const char *salt, char *iobuf)
10660Sstevel@tonic-gate {
10670Sstevel@tonic-gate 	int c, i, j;
10680Sstevel@tonic-gate 	char temp;
10690Sstevel@tonic-gate 	char *block;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	block = iobuf + 16;
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	if (iobuf == 0) {
10740Sstevel@tonic-gate 		errno = ENOMEM;
10750Sstevel@tonic-gate 		return (NULL);
10760Sstevel@tonic-gate 	}
10770Sstevel@tonic-gate 	if (allocate_KS() != 0)
10780Sstevel@tonic-gate 		return (NULL);
10790Sstevel@tonic-gate 	lmutex_lock(&crypt_lock);
10800Sstevel@tonic-gate 	for (i = 0; i < 66; i++)
10810Sstevel@tonic-gate 		block[i] = 0;
10820Sstevel@tonic-gate 	for (i = 0; (c = *pw) != '\0' && i < 64; pw++) {
10830Sstevel@tonic-gate 		for (j = 0; j < 7; j++, i++)
10840Sstevel@tonic-gate 			block[i] = (c>>(6-j)) & 01;
10850Sstevel@tonic-gate 		i++;
10860Sstevel@tonic-gate 	}
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	unlocked_setkey(block);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	for (i = 0; i < 66; i++)
10910Sstevel@tonic-gate 		block[i] = 0;
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
10940Sstevel@tonic-gate 		c = *salt++;
10950Sstevel@tonic-gate 		iobuf[i] = (char)c;
10960Sstevel@tonic-gate 		if (c > 'Z')
10970Sstevel@tonic-gate 			c -= 6;
10980Sstevel@tonic-gate 		if (c > '9')
10990Sstevel@tonic-gate 			c -= 7;
11000Sstevel@tonic-gate 		c -= '.';
11010Sstevel@tonic-gate 		for (j = 0; j < 6; j++) {
11020Sstevel@tonic-gate 			if ((c>>j) & 01) {
11030Sstevel@tonic-gate 				temp = E[6*i+j];
11040Sstevel@tonic-gate 				E[6*i+j] = E[6*i+j+24];
11050Sstevel@tonic-gate 				E[6*i+j+24] = temp;
11060Sstevel@tonic-gate 			}
11070Sstevel@tonic-gate 		}
11080Sstevel@tonic-gate 	}
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	for (i = 0; i < 25; i++)
11110Sstevel@tonic-gate 		unlocked_encrypt(block, 0);
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	lmutex_unlock(&crypt_lock);
11140Sstevel@tonic-gate 	for (i = 0; i < 11; i++) {
11150Sstevel@tonic-gate 		c = 0;
11160Sstevel@tonic-gate 		for (j = 0; j < 6; j++) {
11170Sstevel@tonic-gate 			c <<= 1;
11180Sstevel@tonic-gate 			c |= block[6*i+j];
11190Sstevel@tonic-gate 		}
11200Sstevel@tonic-gate 		c += '.';
11210Sstevel@tonic-gate 		if (c > '9')
11220Sstevel@tonic-gate 			c += 7;
11230Sstevel@tonic-gate 		if (c > 'Z')
11240Sstevel@tonic-gate 			c += 6;
11250Sstevel@tonic-gate 		iobuf[i+2] = (char)c;
11260Sstevel@tonic-gate 	}
11270Sstevel@tonic-gate 	iobuf[i+2] = 0;
11280Sstevel@tonic-gate 	if (iobuf[1] == 0)
11290Sstevel@tonic-gate 		iobuf[1] = iobuf[0];
11300Sstevel@tonic-gate 	return (iobuf);
11310Sstevel@tonic-gate }
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate /*ARGSUSED*/
11350Sstevel@tonic-gate void
encrypt(char * block,int fake)11360Sstevel@tonic-gate encrypt(char *block, int fake)
11370Sstevel@tonic-gate {
11380Sstevel@tonic-gate 	if (fake != 0) {
11390Sstevel@tonic-gate 		errno = ENOSYS;
11400Sstevel@tonic-gate 		return;
11410Sstevel@tonic-gate 	}
11420Sstevel@tonic-gate 	if (allocate_KS() != 0)
11430Sstevel@tonic-gate 		return;
11440Sstevel@tonic-gate 	lmutex_lock(&crypt_lock);
11450Sstevel@tonic-gate 	unlocked_encrypt(block, fake);
11460Sstevel@tonic-gate 	lmutex_unlock(&crypt_lock);
11470Sstevel@tonic-gate }
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate void
setkey(const char * key)11510Sstevel@tonic-gate setkey(const char *key)
11520Sstevel@tonic-gate {
11530Sstevel@tonic-gate 	if (allocate_KS() != 0)
11540Sstevel@tonic-gate 		return;
11550Sstevel@tonic-gate 	lmutex_lock(&crypt_lock);
11560Sstevel@tonic-gate 	unlocked_setkey(key);
11570Sstevel@tonic-gate 	lmutex_unlock(&crypt_lock);
11580Sstevel@tonic-gate }
1159