xref: /onnv-gate/usr/src/lib/libc/port/gen/crypt.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #pragma	weak crypt = _crypt
30*0Sstevel@tonic-gate #pragma weak encrypt = _encrypt
31*0Sstevel@tonic-gate #pragma weak setkey = _setkey
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include "synonyms.h"
34*0Sstevel@tonic-gate #include "mtlib.h"
35*0Sstevel@tonic-gate #include <synch.h>
36*0Sstevel@tonic-gate #include <thread.h>
37*0Sstevel@tonic-gate #include <ctype.h>
38*0Sstevel@tonic-gate #include <dlfcn.h>
39*0Sstevel@tonic-gate #include <errno.h>
40*0Sstevel@tonic-gate #include <stdio.h>
41*0Sstevel@tonic-gate #include <strings.h>
42*0Sstevel@tonic-gate #include <stdlib.h>
43*0Sstevel@tonic-gate #include <sys/time.h>
44*0Sstevel@tonic-gate #include <limits.h>
45*0Sstevel@tonic-gate #include <sys/types.h>
46*0Sstevel@tonic-gate #include <sys/stat.h>
47*0Sstevel@tonic-gate #include <fcntl.h>
48*0Sstevel@tonic-gate #include <syslog.h>
49*0Sstevel@tonic-gate #include <unistd.h>
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate #include <crypt.h>
52*0Sstevel@tonic-gate #include <libc.h>
53*0Sstevel@tonic-gate #include "tsd.h"
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate #define	CRYPT_ALGORITHMS_ALLOW		"CRYPT_ALGORITHMS_ALLOW"
56*0Sstevel@tonic-gate #define	CRYPT_ALGORITHMS_DEPRECATE	"CRYPT_ALGORITHMS_DEPRECATE"
57*0Sstevel@tonic-gate #define	CRYPT_DEFAULT			"CRYPT_DEFAULT"
58*0Sstevel@tonic-gate #define	CRYPT_UNIX			"__unix__"
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #define	CRYPT_CONFFILE		"/etc/security/crypt.conf"
61*0Sstevel@tonic-gate #define	POLICY_CONF_FILE	"/etc/security/policy.conf"
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate #define	CRYPT_CONFLINELENGTH	1024
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #define	CRYPT_MODULE_ISA	"/$ISA/"
66*0Sstevel@tonic-gate #ifdef	_LP64
67*0Sstevel@tonic-gate #define	CRYPT_MODULE_DIR	"/usr/lib/security/64/"
68*0Sstevel@tonic-gate #define	CRYPT_ISA_DIR		"/64/"
69*0Sstevel@tonic-gate #else	/* !_LP64 */
70*0Sstevel@tonic-gate #define	CRYPT_MODULE_DIR	"/usr/lib/security/"
71*0Sstevel@tonic-gate #define	CRYPT_ISA_DIR		"/"
72*0Sstevel@tonic-gate #endif	/* _LP64 */
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate /*
75*0Sstevel@tonic-gate  * MAX_ALGNAME_LEN:
76*0Sstevel@tonic-gate  *
77*0Sstevel@tonic-gate  * In practical terms this is probably never any bigger than about 10, but...
78*0Sstevel@tonic-gate  *
79*0Sstevel@tonic-gate  * It has to fix the encrypted password filed of struct spwd it is
80*0Sstevel@tonic-gate  * theoretically the maximum length of the cipher minus the magic $ sign.
81*0Sstevel@tonic-gate  * Though that would be unexpected.
82*0Sstevel@tonic-gate  * Since it also has to fit in crypt.conf it is CRYPT_CONFLINELENGTH
83*0Sstevel@tonic-gate  * minus the path to the module and the minimum white space.
84*0Sstevel@tonic-gate  *
85*0Sstevel@tonic-gate  * CRYPT_MAXCIPHERTEXTLEN is defined in crypt.h and is smaller than
86*0Sstevel@tonic-gate  * CRYPT_CONFLINELENGTH, and probably always will be.
87*0Sstevel@tonic-gate  */
88*0Sstevel@tonic-gate #define	MAX_ALGNAME_LEN	(CRYPT_MAXCIPHERTEXTLEN - 1)
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate struct crypt_alg_s {
91*0Sstevel@tonic-gate 	void	*a_libhandle;
92*0Sstevel@tonic-gate 	char	*(*a_genhash)(char *, const size_t, const char *,
93*0Sstevel@tonic-gate 		    const char *, const char **);
94*0Sstevel@tonic-gate 	char	*(*a_gensalt)(char *, const size_t,
95*0Sstevel@tonic-gate 		    const char *, const struct passwd *, const char **);
96*0Sstevel@tonic-gate 	char	**a_params;
97*0Sstevel@tonic-gate 	int	a_nparams;
98*0Sstevel@tonic-gate };
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate struct crypt_policy_s {
101*0Sstevel@tonic-gate 	char	*cp_default;
102*0Sstevel@tonic-gate 	char	*cp_allow;
103*0Sstevel@tonic-gate 	char	*cp_deny;
104*0Sstevel@tonic-gate };
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate enum crypt_policy_error_e {
107*0Sstevel@tonic-gate 	CPE_BOTH = 1,
108*0Sstevel@tonic-gate 	CPE_MULTI
109*0Sstevel@tonic-gate };
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate static struct crypt_policy_s *getcryptpolicy(void);
112*0Sstevel@tonic-gate static void free_crypt_policy(struct crypt_policy_s *policy);
113*0Sstevel@tonic-gate static struct crypt_alg_s  *getalgbyname(const char *algname, boolean_t *found);
114*0Sstevel@tonic-gate static void free_crypt_alg(struct crypt_alg_s *alg);
115*0Sstevel@tonic-gate static char *getalgfromsalt(const char *salt);
116*0Sstevel@tonic-gate static boolean_t alg_valid(const char *algname,
117*0Sstevel@tonic-gate     const struct crypt_policy_s *policy);
118*0Sstevel@tonic-gate static char *isa_path(const char *path);
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate static char *_unix_crypt(const char *pw, const char *salt, char *iobuf);
121*0Sstevel@tonic-gate static char *_unix_crypt_gensalt(char *gsbuffer, size_t gsbufflen,
122*0Sstevel@tonic-gate 	    const char *oldpuresalt, const struct passwd *userinfo,
123*0Sstevel@tonic-gate 	    const char *params[]);
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate /*
127*0Sstevel@tonic-gate  * crypt - string encoding function
128*0Sstevel@tonic-gate  *
129*0Sstevel@tonic-gate  * This function encodes strings in a suitable for for secure storage
130*0Sstevel@tonic-gate  * as passwords.  It generates the password hash given the plaintext and salt.
131*0Sstevel@tonic-gate  *
132*0Sstevel@tonic-gate  * If the first character of salt is "$" then we use crypt.conf(4) to
133*0Sstevel@tonic-gate  * determine which plugin to use and run the crypt_genhash_impl(3c) function
134*0Sstevel@tonic-gate  * from it.
135*0Sstevel@tonic-gate  * Otherwise we use the old unix algorithm.
136*0Sstevel@tonic-gate  *
137*0Sstevel@tonic-gate  * RETURN VALUES
138*0Sstevel@tonic-gate  *	On Success we return a pointer to the encoded string.  The
139*0Sstevel@tonic-gate  *	return value points to thread specific static data and should NOT
140*0Sstevel@tonic-gate  *	be passed free(3c).
141*0Sstevel@tonic-gate  *	On failure we return NULL and set errno to one of:
142*0Sstevel@tonic-gate  *		EINVAL, ELIBACC, ENOMEM, ENOSYS.
143*0Sstevel@tonic-gate  */
144*0Sstevel@tonic-gate char *
145*0Sstevel@tonic-gate crypt(const char *plaintext, const char *salt)
146*0Sstevel@tonic-gate {
147*0Sstevel@tonic-gate 	struct crypt_alg_s *alg;
148*0Sstevel@tonic-gate 	char *ctbuffer;
149*0Sstevel@tonic-gate 	char *ciphertext;
150*0Sstevel@tonic-gate 	char *algname;
151*0Sstevel@tonic-gate 	boolean_t found;
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	ctbuffer = tsdalloc(_T_CRYPT, CRYPT_MAXCIPHERTEXTLEN, NULL);
154*0Sstevel@tonic-gate 	if (ctbuffer == NULL)
155*0Sstevel@tonic-gate 		return (NULL);
156*0Sstevel@tonic-gate 	bzero(ctbuffer, CRYPT_MAXCIPHERTEXTLEN);
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	/*
159*0Sstevel@tonic-gate 	 * '$' is never a possible salt char with the traditional unix
160*0Sstevel@tonic-gate 	 * algorithm.  If the salt passed in is NULL or the first char
161*0Sstevel@tonic-gate 	 * of the salt isn't a $ then do the traditional thing.
162*0Sstevel@tonic-gate 	 * We also do the traditional thing if the salt is only 1 char.
163*0Sstevel@tonic-gate 	 */
164*0Sstevel@tonic-gate 	if (salt == NULL || salt[0] != '$' || strlen(salt) == 1) {
165*0Sstevel@tonic-gate 		return (_unix_crypt(plaintext, salt, ctbuffer));
166*0Sstevel@tonic-gate 	}
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	/*
169*0Sstevel@tonic-gate 	 * Find the algorithm name from the salt and look it up in
170*0Sstevel@tonic-gate 	 * crypt.conf(4) to find out what shared object to use.
171*0Sstevel@tonic-gate 	 * If we can't find it in crypt.conf then getalgbyname would
172*0Sstevel@tonic-gate 	 * have returned with found = B_FALSE so we use the unix algorithm.
173*0Sstevel@tonic-gate 	 * If alg is NULL but found = B_TRUE then there is a problem with
174*0Sstevel@tonic-gate 	 * the plugin so we fail leaving errno set to what getalgbyname()
175*0Sstevel@tonic-gate 	 * set it to or EINVAL it if wasn't set.
176*0Sstevel@tonic-gate 	 */
177*0Sstevel@tonic-gate 	if ((algname = getalgfromsalt(salt)) == NULL) {
178*0Sstevel@tonic-gate 		return (NULL);
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	errno = 0;
182*0Sstevel@tonic-gate 	alg = getalgbyname(algname, &found);
183*0Sstevel@tonic-gate 	if ((alg == NULL) || !found) {
184*0Sstevel@tonic-gate 		if (errno == 0)
185*0Sstevel@tonic-gate 			errno = EINVAL;
186*0Sstevel@tonic-gate 		ciphertext = NULL;
187*0Sstevel@tonic-gate 		goto cleanup;
188*0Sstevel@tonic-gate 	} else if (!found) {
189*0Sstevel@tonic-gate 		ciphertext = _unix_crypt(plaintext, salt, ctbuffer);
190*0Sstevel@tonic-gate 	} else {
191*0Sstevel@tonic-gate 		ciphertext = alg->a_genhash(ctbuffer, CRYPT_MAXCIPHERTEXTLEN,
192*0Sstevel@tonic-gate 		    plaintext, salt, (const char **)alg->a_params);
193*0Sstevel@tonic-gate 	}
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate cleanup:
196*0Sstevel@tonic-gate 	free_crypt_alg(alg);
197*0Sstevel@tonic-gate 	if (algname != NULL)
198*0Sstevel@tonic-gate 		free(algname);
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	return (ciphertext);
201*0Sstevel@tonic-gate }
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate /*
204*0Sstevel@tonic-gate  * crypt_gensalt - generate salt string for string encoding
205*0Sstevel@tonic-gate  *
206*0Sstevel@tonic-gate  * This function generates the salt string pased to crypt(3c).
207*0Sstevel@tonic-gate  * If oldsalt is NULL, the use the default algorithm.
208*0Sstevel@tonic-gate  * Other wise check the policy in policy.conf to ensure that it is
209*0Sstevel@tonic-gate  * either still allowed or not deprecated.
210*0Sstevel@tonic-gate  *
211*0Sstevel@tonic-gate  * RETURN VALUES
212*0Sstevel@tonic-gate  * 	Return a pointer to the new salt, the caller is responsible
213*0Sstevel@tonic-gate  * 	for using free(3c) on the return value.
214*0Sstevel@tonic-gate  * 	Returns NULL on error and sets errno to one of:
215*0Sstevel@tonic-gate  * 		EINVAL, ELIBACC, ENOMEM
216*0Sstevel@tonic-gate  */
217*0Sstevel@tonic-gate char *
218*0Sstevel@tonic-gate crypt_gensalt(const char *oldsalt, const struct passwd *userinfo)
219*0Sstevel@tonic-gate {
220*0Sstevel@tonic-gate 	struct crypt_alg_s *alg = NULL;
221*0Sstevel@tonic-gate 	struct crypt_policy_s *policy = NULL;
222*0Sstevel@tonic-gate 	char *newsalt = NULL;
223*0Sstevel@tonic-gate 	char *gsbuffer;
224*0Sstevel@tonic-gate 	char *algname = NULL;
225*0Sstevel@tonic-gate 	boolean_t found;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	gsbuffer = calloc(CRYPT_MAXCIPHERTEXTLEN, sizeof (char *));
228*0Sstevel@tonic-gate 	if (gsbuffer == NULL) {
229*0Sstevel@tonic-gate 		errno = ENOMEM;
230*0Sstevel@tonic-gate 		goto cleanup;
231*0Sstevel@tonic-gate 	}
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	policy = getcryptpolicy();
234*0Sstevel@tonic-gate 	if (policy == NULL) {
235*0Sstevel@tonic-gate 		errno = EINVAL;
236*0Sstevel@tonic-gate 		goto cleanup;
237*0Sstevel@tonic-gate 	}
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	algname = getalgfromsalt(oldsalt);
240*0Sstevel@tonic-gate 	if (!alg_valid(algname, policy)) {
241*0Sstevel@tonic-gate 		free(algname);
242*0Sstevel@tonic-gate 		algname = strdup(policy->cp_default);
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	if (strcmp(algname, CRYPT_UNIX) == 0) {
246*0Sstevel@tonic-gate 		newsalt = _unix_crypt_gensalt(gsbuffer, CRYPT_MAXCIPHERTEXTLEN,
247*0Sstevel@tonic-gate 		    oldsalt, userinfo, NULL);
248*0Sstevel@tonic-gate 	} else {
249*0Sstevel@tonic-gate 		errno = 0;
250*0Sstevel@tonic-gate 		alg = getalgbyname(algname, &found);
251*0Sstevel@tonic-gate 		if (alg == NULL || !found) {
252*0Sstevel@tonic-gate 			if (errno == 0)
253*0Sstevel@tonic-gate 				errno = EINVAL;
254*0Sstevel@tonic-gate 			goto cleanup;
255*0Sstevel@tonic-gate 		}
256*0Sstevel@tonic-gate 		newsalt = alg->a_gensalt(gsbuffer, CRYPT_MAXCIPHERTEXTLEN,
257*0Sstevel@tonic-gate 		    oldsalt, userinfo, (const char **)alg->a_params);
258*0Sstevel@tonic-gate 	}
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate cleanup:
261*0Sstevel@tonic-gate 	free_crypt_policy(policy);
262*0Sstevel@tonic-gate 	free_crypt_alg(alg);
263*0Sstevel@tonic-gate 	if (newsalt == NULL && gsbuffer != NULL)
264*0Sstevel@tonic-gate 		free(gsbuffer);
265*0Sstevel@tonic-gate 	if (algname != NULL)
266*0Sstevel@tonic-gate 		free(algname);
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	return (newsalt);
269*0Sstevel@tonic-gate }
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate /*
272*0Sstevel@tonic-gate  * ===========================================================================
273*0Sstevel@tonic-gate  * The remainder of this file contains internal interfaces for
274*0Sstevel@tonic-gate  * the implementation of crypt(3c) and crypt_gensalt(3c)
275*0Sstevel@tonic-gate  * ===========================================================================
276*0Sstevel@tonic-gate  */
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate /*
280*0Sstevel@tonic-gate  * getalgfromsalt - extract the algorithm name from the salt string
281*0Sstevel@tonic-gate  */
282*0Sstevel@tonic-gate static char *
283*0Sstevel@tonic-gate getalgfromsalt(const char *salt)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	char algname[CRYPT_MAXCIPHERTEXTLEN];
286*0Sstevel@tonic-gate 	int i;
287*0Sstevel@tonic-gate 	int j;
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	if (salt == NULL || strlen(salt) > CRYPT_MAXCIPHERTEXTLEN)
290*0Sstevel@tonic-gate 		return (NULL);
291*0Sstevel@tonic-gate 	/*
292*0Sstevel@tonic-gate 	 * Salts are in this format:
293*0Sstevel@tonic-gate 	 * $<algname>[,var=val,[var=val ...][$puresalt]$<ciphertext>
294*0Sstevel@tonic-gate 	 *
295*0Sstevel@tonic-gate 	 * The only bit we need to worry about here is extracting the
296*0Sstevel@tonic-gate 	 * name which is the string between the first "$" and the first
297*0Sstevel@tonic-gate 	 * of "," or second "$".
298*0Sstevel@tonic-gate 	 */
299*0Sstevel@tonic-gate 	if (salt[0] != '$') {
300*0Sstevel@tonic-gate 		return (strdup(CRYPT_UNIX));
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	i = 1;
304*0Sstevel@tonic-gate 	j = 0;
305*0Sstevel@tonic-gate 	while (salt[i] != '\0' && salt[i] != '$' && salt[i] != ',') {
306*0Sstevel@tonic-gate 		algname[j] = salt[i];
307*0Sstevel@tonic-gate 		i++;
308*0Sstevel@tonic-gate 		j++;
309*0Sstevel@tonic-gate 	}
310*0Sstevel@tonic-gate 	if (j == 0)
311*0Sstevel@tonic-gate 		return (NULL);
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	algname[j] = '\0';
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	return (strdup(algname));
316*0Sstevel@tonic-gate }
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate /*
320*0Sstevel@tonic-gate  * log_invalid_policy - syslog helper
321*0Sstevel@tonic-gate  */
322*0Sstevel@tonic-gate static void
323*0Sstevel@tonic-gate log_invalid_policy(enum crypt_policy_error_e error, char *value)
324*0Sstevel@tonic-gate {
325*0Sstevel@tonic-gate 	switch (error) {
326*0Sstevel@tonic-gate 	case CPE_BOTH:
327*0Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
328*0Sstevel@tonic-gate 		    "crypt(3c): %s contains both %s and %s; only one may be "
329*0Sstevel@tonic-gate 		    "specified, using first entry in file.", POLICY_CONF_FILE,
330*0Sstevel@tonic-gate 		    CRYPT_ALGORITHMS_ALLOW, CRYPT_ALGORITHMS_DEPRECATE);
331*0Sstevel@tonic-gate 		break;
332*0Sstevel@tonic-gate 	case CPE_MULTI:
333*0Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
334*0Sstevel@tonic-gate 		    "crypt(3c): %s contains multiple %s entries;"
335*0Sstevel@tonic-gate 		    "using first entry file.", POLICY_CONF_FILE, value);
336*0Sstevel@tonic-gate 		break;
337*0Sstevel@tonic-gate 	}
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate static char *
341*0Sstevel@tonic-gate getval(const char *ival)
342*0Sstevel@tonic-gate {
343*0Sstevel@tonic-gate 	char *tmp;
344*0Sstevel@tonic-gate 	char *oval;
345*0Sstevel@tonic-gate 	int off;
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	if (ival == NULL)
348*0Sstevel@tonic-gate 		return (NULL);
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	if ((tmp = strchr(ival, '=')) == NULL)
351*0Sstevel@tonic-gate 		return (NULL);
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate 	oval = strdup(tmp + 1);	/* everything after the "=" */
354*0Sstevel@tonic-gate 	if (oval == NULL)
355*0Sstevel@tonic-gate 		return (NULL);
356*0Sstevel@tonic-gate 	off = strlen(oval) - 1;
357*0Sstevel@tonic-gate 	if (off < 0) {
358*0Sstevel@tonic-gate 		free(oval);
359*0Sstevel@tonic-gate 		return (NULL);
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 	if (oval[off] == '\n')
362*0Sstevel@tonic-gate 		oval[off] = '\0';
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	return (oval);
365*0Sstevel@tonic-gate }
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate /*
368*0Sstevel@tonic-gate  * getcryptpolicy - read /etc/security/policy.conf into a crypt_policy_s
369*0Sstevel@tonic-gate  */
370*0Sstevel@tonic-gate static struct crypt_policy_s *
371*0Sstevel@tonic-gate getcryptpolicy(void)
372*0Sstevel@tonic-gate {
373*0Sstevel@tonic-gate 	FILE	*pconf;
374*0Sstevel@tonic-gate 	char	line[BUFSIZ];
375*0Sstevel@tonic-gate 	struct crypt_policy_s *policy;
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	if ((pconf = fopen(POLICY_CONF_FILE, "r")) == NULL) {
378*0Sstevel@tonic-gate 		return (NULL);
379*0Sstevel@tonic-gate 	}
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	policy = malloc(sizeof (struct crypt_policy_s));
382*0Sstevel@tonic-gate 	if (policy == NULL) {
383*0Sstevel@tonic-gate 		return (NULL);
384*0Sstevel@tonic-gate 	}
385*0Sstevel@tonic-gate 	policy->cp_default = NULL;
386*0Sstevel@tonic-gate 	policy->cp_allow = NULL;
387*0Sstevel@tonic-gate 	policy->cp_deny = NULL;
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	while (!feof(pconf) &&
390*0Sstevel@tonic-gate 	    (fgets(line, sizeof (line), pconf) != NULL)) {
391*0Sstevel@tonic-gate 		if (strncasecmp(CRYPT_DEFAULT, line,
392*0Sstevel@tonic-gate 		    strlen(CRYPT_DEFAULT)) == 0) {
393*0Sstevel@tonic-gate 			if (policy->cp_default != NULL) {
394*0Sstevel@tonic-gate 				log_invalid_policy(CPE_MULTI, CRYPT_DEFAULT);
395*0Sstevel@tonic-gate 			} else {
396*0Sstevel@tonic-gate 				policy->cp_default = getval(line);
397*0Sstevel@tonic-gate 			}
398*0Sstevel@tonic-gate 		}
399*0Sstevel@tonic-gate 		if (strncasecmp(CRYPT_ALGORITHMS_ALLOW, line,
400*0Sstevel@tonic-gate 		    strlen(CRYPT_ALGORITHMS_ALLOW)) == 0) {
401*0Sstevel@tonic-gate 			if (policy->cp_deny != NULL) {
402*0Sstevel@tonic-gate 				log_invalid_policy(CPE_BOTH, NULL);
403*0Sstevel@tonic-gate 			} else if (policy->cp_allow != NULL) {
404*0Sstevel@tonic-gate 				log_invalid_policy(CPE_MULTI,
405*0Sstevel@tonic-gate 				    CRYPT_ALGORITHMS_ALLOW);
406*0Sstevel@tonic-gate 			} else {
407*0Sstevel@tonic-gate 				policy->cp_allow = getval(line);
408*0Sstevel@tonic-gate 			}
409*0Sstevel@tonic-gate 		}
410*0Sstevel@tonic-gate 		if (strncasecmp(CRYPT_ALGORITHMS_DEPRECATE, line,
411*0Sstevel@tonic-gate 		    strlen(CRYPT_ALGORITHMS_DEPRECATE)) == 0) {
412*0Sstevel@tonic-gate 			if (policy->cp_allow != NULL) {
413*0Sstevel@tonic-gate 				log_invalid_policy(CPE_BOTH, NULL);
414*0Sstevel@tonic-gate 			} else if (policy->cp_deny != NULL) {
415*0Sstevel@tonic-gate 				log_invalid_policy(CPE_MULTI,
416*0Sstevel@tonic-gate 				    CRYPT_ALGORITHMS_DEPRECATE);
417*0Sstevel@tonic-gate 			} else {
418*0Sstevel@tonic-gate 				policy->cp_deny = getval(line);
419*0Sstevel@tonic-gate 			}
420*0Sstevel@tonic-gate 		}
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 	(void) fclose(pconf);
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	if (policy->cp_default == NULL) {
425*0Sstevel@tonic-gate 		policy->cp_default = strdup(CRYPT_UNIX);
426*0Sstevel@tonic-gate 		if (policy->cp_default == NULL)
427*0Sstevel@tonic-gate 			free_crypt_policy(policy);
428*0Sstevel@tonic-gate 	}
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	return (policy);
431*0Sstevel@tonic-gate }
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate /*
435*0Sstevel@tonic-gate  * alg_valid - is this algorithm valid given the policy ?
436*0Sstevel@tonic-gate  */
437*0Sstevel@tonic-gate static boolean_t
438*0Sstevel@tonic-gate alg_valid(const char *algname, const struct crypt_policy_s *policy)
439*0Sstevel@tonic-gate {
440*0Sstevel@tonic-gate 	char *lasts;
441*0Sstevel@tonic-gate 	char *list;
442*0Sstevel@tonic-gate 	char *entry;
443*0Sstevel@tonic-gate 	boolean_t allowed = B_FALSE;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if ((algname == NULL) || (policy == NULL)) {
446*0Sstevel@tonic-gate 		return (B_FALSE);
447*0Sstevel@tonic-gate 	}
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 	if (strcmp(algname, policy->cp_default) == 0) {
450*0Sstevel@tonic-gate 		return (B_TRUE);
451*0Sstevel@tonic-gate 	}
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	if (policy->cp_deny != NULL) {
454*0Sstevel@tonic-gate 		list = policy->cp_deny;
455*0Sstevel@tonic-gate 		allowed = B_FALSE;
456*0Sstevel@tonic-gate 	} else if (policy->cp_allow != NULL) {
457*0Sstevel@tonic-gate 		list = policy->cp_allow;
458*0Sstevel@tonic-gate 		allowed = B_TRUE;
459*0Sstevel@tonic-gate 	} else {
460*0Sstevel@tonic-gate 		/*
461*0Sstevel@tonic-gate 		 * Neither of allow or deny policies are set so anything goes.
462*0Sstevel@tonic-gate 		 */
463*0Sstevel@tonic-gate 		return (B_TRUE);
464*0Sstevel@tonic-gate 	}
465*0Sstevel@tonic-gate 	lasts = list;
466*0Sstevel@tonic-gate 	while ((entry = strtok_r(NULL, ",", &lasts)) != NULL) {
467*0Sstevel@tonic-gate 		if (strcmp(entry, algname) == 0) {
468*0Sstevel@tonic-gate 			return (allowed);
469*0Sstevel@tonic-gate 		}
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	return (!allowed);
473*0Sstevel@tonic-gate }
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate /*
476*0Sstevel@tonic-gate  * getalgbyname - read crypt.conf(4) looking for algname
477*0Sstevel@tonic-gate  *
478*0Sstevel@tonic-gate  * RETURN VALUES
479*0Sstevel@tonic-gate  *	On error NULL and errno is set
480*0Sstevel@tonic-gate  *	On success the alg details including an open handle to the lib
481*0Sstevel@tonic-gate  *	If crypt.conf(4) is okay but algname doesn't exist in it then
482*0Sstevel@tonic-gate  *	return NULL the caller should then use the default algorithm
483*0Sstevel@tonic-gate  *	as per the policy.
484*0Sstevel@tonic-gate  */
485*0Sstevel@tonic-gate static struct crypt_alg_s *
486*0Sstevel@tonic-gate getalgbyname(const char *algname, boolean_t *found)
487*0Sstevel@tonic-gate {
488*0Sstevel@tonic-gate 	struct stat	stb;
489*0Sstevel@tonic-gate 	int		configfd;
490*0Sstevel@tonic-gate 	FILE		*fconf = NULL;
491*0Sstevel@tonic-gate 	struct crypt_alg_s *alg = NULL;
492*0Sstevel@tonic-gate 	char		line[CRYPT_CONFLINELENGTH];
493*0Sstevel@tonic-gate 	int		linelen = 0;
494*0Sstevel@tonic-gate 	int		lineno = 0;
495*0Sstevel@tonic-gate 	char		*pathname = NULL;
496*0Sstevel@tonic-gate 	char		*lasts = NULL;
497*0Sstevel@tonic-gate 	char		*token = NULL;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	*found = B_FALSE;
500*0Sstevel@tonic-gate 	if ((algname == NULL) || (strcmp(algname, CRYPT_UNIX) == 0)) {
501*0Sstevel@tonic-gate 		return (NULL);
502*0Sstevel@tonic-gate 	}
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	if ((configfd = open(CRYPT_CONFFILE, O_RDONLY)) == -1) {
505*0Sstevel@tonic-gate 		syslog(LOG_ALERT, "crypt: open(%s) failed: %s",
506*0Sstevel@tonic-gate 			CRYPT_CONFFILE, strerror(errno));
507*0Sstevel@tonic-gate 		return (NULL);
508*0Sstevel@tonic-gate 	}
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	/*
511*0Sstevel@tonic-gate 	 * Stat the file so we can check modes and ownerships
512*0Sstevel@tonic-gate 	 */
513*0Sstevel@tonic-gate 	if (fstat(configfd, &stb) < 0) {
514*0Sstevel@tonic-gate 		syslog(LOG_ALERT, "crypt: stat(%s) failed: %s",
515*0Sstevel@tonic-gate 			CRYPT_CONFFILE, strerror(errno));
516*0Sstevel@tonic-gate 		goto cleanup;
517*0Sstevel@tonic-gate 	}
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	/*
520*0Sstevel@tonic-gate 	 * Check the ownership of the file
521*0Sstevel@tonic-gate 	 */
522*0Sstevel@tonic-gate 	if (stb.st_uid != (uid_t)0) {
523*0Sstevel@tonic-gate 		syslog(LOG_ALERT,
524*0Sstevel@tonic-gate 		    "crypt: Owner of %s is not root", CRYPT_CONFFILE);
525*0Sstevel@tonic-gate 		goto cleanup;
526*0Sstevel@tonic-gate 	}
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	/*
529*0Sstevel@tonic-gate 	 * Check the modes on the file
530*0Sstevel@tonic-gate 	 */
531*0Sstevel@tonic-gate 	if (stb.st_mode & S_IWGRP) {
532*0Sstevel@tonic-gate 		syslog(LOG_ALERT,
533*0Sstevel@tonic-gate 		    "crypt: %s writable by group", CRYPT_CONFFILE);
534*0Sstevel@tonic-gate 		goto cleanup;
535*0Sstevel@tonic-gate 	}
536*0Sstevel@tonic-gate 	if (stb.st_mode & S_IWOTH) {
537*0Sstevel@tonic-gate 		syslog(LOG_ALERT,
538*0Sstevel@tonic-gate 			"crypt: %s writable by world", CRYPT_CONFFILE);
539*0Sstevel@tonic-gate 		goto cleanup;
540*0Sstevel@tonic-gate 	}
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	if ((fconf = fdopen(configfd, "r")) == NULL) {
543*0Sstevel@tonic-gate 		syslog(LOG_ALERT, "crypt: fdopen(%d) failed: %s",
544*0Sstevel@tonic-gate 			configfd, strerror(errno));
545*0Sstevel@tonic-gate 		goto cleanup;
546*0Sstevel@tonic-gate 	}
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 	/*
549*0Sstevel@tonic-gate 	 * /etc/security/crypt.conf has 3 fields:
550*0Sstevel@tonic-gate 	 * <algname>	<pathname>	[<name[=val]>[<name[=val]>]]
551*0Sstevel@tonic-gate 	 */
552*0Sstevel@tonic-gate 	errno = 0;
553*0Sstevel@tonic-gate 	while (!(*found) &&
554*0Sstevel@tonic-gate 	    ((fgets(line, sizeof (line), fconf) != NULL) && !feof(fconf))) {
555*0Sstevel@tonic-gate 		lineno++;
556*0Sstevel@tonic-gate 		/*
557*0Sstevel@tonic-gate 		 * Skip over comments
558*0Sstevel@tonic-gate 		 */
559*0Sstevel@tonic-gate 		if ((line[0] == '#') || (line[0] == '\n')) {
560*0Sstevel@tonic-gate 			continue;
561*0Sstevel@tonic-gate 		}
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 		linelen = strlen(line);
564*0Sstevel@tonic-gate 		line[--linelen] = '\0';	/* chop the trailing \n */
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 		token = strtok_r(line, " \t", &lasts);
567*0Sstevel@tonic-gate 		if (token == NULL) {
568*0Sstevel@tonic-gate 			continue;
569*0Sstevel@tonic-gate 		}
570*0Sstevel@tonic-gate 		if (strcmp(token, algname) == 0) {
571*0Sstevel@tonic-gate 			*found = B_TRUE;
572*0Sstevel@tonic-gate 		}
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate 	if (!found) {
575*0Sstevel@tonic-gate 		errno = EINVAL;
576*0Sstevel@tonic-gate 		goto cleanup;
577*0Sstevel@tonic-gate 	}
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 	token = strtok_r(NULL, " \t", &lasts);
580*0Sstevel@tonic-gate 	if (token == NULL) {
581*0Sstevel@tonic-gate 		/*
582*0Sstevel@tonic-gate 		 * Broken config file
583*0Sstevel@tonic-gate 		 */
584*0Sstevel@tonic-gate 		syslog(LOG_ALERT, "crypt(3c): %s may be corrupt at line %d",
585*0Sstevel@tonic-gate 		    CRYPT_CONFFILE, lineno);
586*0Sstevel@tonic-gate 		*found = B_FALSE;
587*0Sstevel@tonic-gate 		errno = EINVAL;
588*0Sstevel@tonic-gate 		goto cleanup;
589*0Sstevel@tonic-gate 	}
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 	if ((pathname = isa_path(token)) == NULL) {
592*0Sstevel@tonic-gate 		if (errno != ENOMEM)
593*0Sstevel@tonic-gate 			errno = EINVAL;
594*0Sstevel@tonic-gate 		*found = B_FALSE;
595*0Sstevel@tonic-gate 		goto cleanup;
596*0Sstevel@tonic-gate 	}
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate 	if ((alg = malloc(sizeof (struct crypt_alg_s))) == NULL) {
599*0Sstevel@tonic-gate 		*found = B_FALSE;
600*0Sstevel@tonic-gate 		goto cleanup;
601*0Sstevel@tonic-gate 	}
602*0Sstevel@tonic-gate 	alg->a_libhandle = NULL;
603*0Sstevel@tonic-gate 	alg->a_genhash = NULL;
604*0Sstevel@tonic-gate 	alg->a_gensalt = NULL;
605*0Sstevel@tonic-gate 	alg->a_params = NULL;
606*0Sstevel@tonic-gate 	alg->a_nparams = 0;
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	/*
609*0Sstevel@tonic-gate 	 * The rest of the line is module specific params, space
610*0Sstevel@tonic-gate 	 * seprated. We wait until after we have checked the module is
611*0Sstevel@tonic-gate 	 * valid before parsing them into a_params, this saves us
612*0Sstevel@tonic-gate 	 * having to free them later if there is a problem.
613*0Sstevel@tonic-gate 	 */
614*0Sstevel@tonic-gate 	if ((alg->a_libhandle = dlopen(pathname, RTLD_NOW)) == NULL) {
615*0Sstevel@tonic-gate 		syslog(LOG_ERR, "crypt(3c) unable to dlopen %s: %s",
616*0Sstevel@tonic-gate 		    pathname, dlerror());
617*0Sstevel@tonic-gate 		errno = ELIBACC;
618*0Sstevel@tonic-gate 		*found = B_FALSE;
619*0Sstevel@tonic-gate 		goto cleanup;
620*0Sstevel@tonic-gate 	}
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	alg->a_genhash =
623*0Sstevel@tonic-gate 	    (char *(*)())dlsym(alg->a_libhandle, "crypt_genhash_impl");
624*0Sstevel@tonic-gate 	if (alg->a_genhash == NULL) {
625*0Sstevel@tonic-gate 		syslog(LOG_ERR, "crypt(3c) unable to find cryp_genhash_impl"
626*0Sstevel@tonic-gate 		    "symbol in %s: %s", pathname, dlerror());
627*0Sstevel@tonic-gate 		errno = ELIBACC;
628*0Sstevel@tonic-gate 		*found = B_FALSE;
629*0Sstevel@tonic-gate 		goto cleanup;
630*0Sstevel@tonic-gate 	}
631*0Sstevel@tonic-gate 	alg->a_gensalt =
632*0Sstevel@tonic-gate 	    (char *(*)())dlsym(alg->a_libhandle, "crypt_gensalt_impl");
633*0Sstevel@tonic-gate 	if (alg->a_gensalt == NULL) {
634*0Sstevel@tonic-gate 		syslog(LOG_ERR, "crypt(3c) unable to find crypt_gensalt_impl"
635*0Sstevel@tonic-gate 		    "symbol in %s: %s", pathname, dlerror());
636*0Sstevel@tonic-gate 		errno = ELIBACC;
637*0Sstevel@tonic-gate 		*found = B_FALSE;
638*0Sstevel@tonic-gate 		goto cleanup;
639*0Sstevel@tonic-gate 	}
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	/*
642*0Sstevel@tonic-gate 	 * We have a good module so build the a_params if we have any.
643*0Sstevel@tonic-gate 	 * Count how much space we need first and then allocate an array
644*0Sstevel@tonic-gate 	 * to hold that many module params.
645*0Sstevel@tonic-gate 	 */
646*0Sstevel@tonic-gate 	if (lasts != NULL) {
647*0Sstevel@tonic-gate 		int nparams = 0;
648*0Sstevel@tonic-gate 		char *tparams;
649*0Sstevel@tonic-gate 		char *tplasts;
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 		if ((tparams = strdup(lasts)) == NULL) {
652*0Sstevel@tonic-gate 			*found = B_FALSE;
653*0Sstevel@tonic-gate 			goto cleanup;
654*0Sstevel@tonic-gate 		}
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 		(void) strtok_r(tparams, " \t", &tplasts);
657*0Sstevel@tonic-gate 		do {
658*0Sstevel@tonic-gate 			nparams++;
659*0Sstevel@tonic-gate 		} while (strtok_r(NULL, " \t", &tplasts) != NULL);
660*0Sstevel@tonic-gate 		free(tparams);
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 		alg->a_params = calloc(nparams + 1, sizeof (char *));
663*0Sstevel@tonic-gate 		if (alg->a_params == NULL) {
664*0Sstevel@tonic-gate 			*found = B_FALSE;
665*0Sstevel@tonic-gate 			goto cleanup;
666*0Sstevel@tonic-gate 		}
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 		while ((token = strtok_r(NULL, " \t", &lasts)) != NULL) {
669*0Sstevel@tonic-gate 			alg->a_params[alg->a_nparams++] = token;
670*0Sstevel@tonic-gate 		}
671*0Sstevel@tonic-gate 	}
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate cleanup:
674*0Sstevel@tonic-gate 	if (*found == B_FALSE) {
675*0Sstevel@tonic-gate 		free_crypt_alg(alg);
676*0Sstevel@tonic-gate 		alg = NULL;
677*0Sstevel@tonic-gate 	}
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 	if (pathname != NULL) {
680*0Sstevel@tonic-gate 		free(pathname);
681*0Sstevel@tonic-gate 	}
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 	if (fconf != NULL) {
684*0Sstevel@tonic-gate 		(void) fclose(fconf);
685*0Sstevel@tonic-gate 	} else {
686*0Sstevel@tonic-gate 		(void) close(configfd);
687*0Sstevel@tonic-gate 	}
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate 	return (alg);
690*0Sstevel@tonic-gate }
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate static void
693*0Sstevel@tonic-gate free_crypt_alg(struct crypt_alg_s *alg)
694*0Sstevel@tonic-gate {
695*0Sstevel@tonic-gate 	if (alg == NULL)
696*0Sstevel@tonic-gate 		return;
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	if (alg->a_libhandle != NULL) {
699*0Sstevel@tonic-gate 		(void) dlclose(alg->a_libhandle);
700*0Sstevel@tonic-gate 	}
701*0Sstevel@tonic-gate 	if (alg->a_nparams != NULL) {
702*0Sstevel@tonic-gate 		free(alg->a_params);
703*0Sstevel@tonic-gate 	}
704*0Sstevel@tonic-gate 	free(alg);
705*0Sstevel@tonic-gate }
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate static void
708*0Sstevel@tonic-gate free_crypt_policy(struct crypt_policy_s *policy)
709*0Sstevel@tonic-gate {
710*0Sstevel@tonic-gate 	if (policy == NULL)
711*0Sstevel@tonic-gate 		return;
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	if (policy->cp_default != NULL) {
714*0Sstevel@tonic-gate 		bzero(policy->cp_default, strlen(policy->cp_default));
715*0Sstevel@tonic-gate 		free(policy->cp_default);
716*0Sstevel@tonic-gate 		policy->cp_default = NULL;
717*0Sstevel@tonic-gate 	}
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 	if (policy->cp_allow != NULL) {
720*0Sstevel@tonic-gate 		bzero(policy->cp_allow, strlen(policy->cp_allow));
721*0Sstevel@tonic-gate 		free(policy->cp_allow);
722*0Sstevel@tonic-gate 		policy->cp_allow = NULL;
723*0Sstevel@tonic-gate 	}
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 	if (policy->cp_deny != NULL) {
726*0Sstevel@tonic-gate 		bzero(policy->cp_deny, strlen(policy->cp_deny));
727*0Sstevel@tonic-gate 		free(policy->cp_deny);
728*0Sstevel@tonic-gate 		policy->cp_deny = NULL;
729*0Sstevel@tonic-gate 	}
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	free(policy);
732*0Sstevel@tonic-gate }
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate /*
736*0Sstevel@tonic-gate  * isa_path - prepend the default dir or patch up the $ISA in path
737*0Sstevel@tonic-gate  * 	Caller is responsible for calling free(3c) on the result.
738*0Sstevel@tonic-gate  */
739*0Sstevel@tonic-gate static char *
740*0Sstevel@tonic-gate isa_path(const char *path)
741*0Sstevel@tonic-gate {
742*0Sstevel@tonic-gate 	char *ret = NULL;
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	if ((path == NULL) || (strlen(path) > PATH_MAX)) {
745*0Sstevel@tonic-gate 		return (NULL);
746*0Sstevel@tonic-gate 	}
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 	ret = calloc(PATH_MAX, sizeof (char));
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 	/*
751*0Sstevel@tonic-gate 	 * Module path doesn't start with "/" then prepend
752*0Sstevel@tonic-gate 	 * the default search path CRYPT_MODULE_DIR (/usr/lib/security/$ISA)
753*0Sstevel@tonic-gate 	 */
754*0Sstevel@tonic-gate 	if (path[0] != '/') {
755*0Sstevel@tonic-gate 		if (snprintf(ret, PATH_MAX, "%s%s", CRYPT_MODULE_DIR,
756*0Sstevel@tonic-gate 		    path) > PATH_MAX) {
757*0Sstevel@tonic-gate 			free(ret);
758*0Sstevel@tonic-gate 			return (NULL);
759*0Sstevel@tonic-gate 		}
760*0Sstevel@tonic-gate 	} else { /* patch up $ISA */
761*0Sstevel@tonic-gate 		char *isa;
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 		if ((isa = strstr(path, CRYPT_MODULE_ISA)) != NULL) {
764*0Sstevel@tonic-gate 			*isa = '\0';
765*0Sstevel@tonic-gate 			isa += strlen(CRYPT_MODULE_ISA);
766*0Sstevel@tonic-gate 			if (snprintf(ret, PATH_MAX, "%s%s%s", path,
767*0Sstevel@tonic-gate 			    CRYPT_ISA_DIR, isa) > PATH_MAX) {
768*0Sstevel@tonic-gate 				free(ret);
769*0Sstevel@tonic-gate 				return (NULL);
770*0Sstevel@tonic-gate 			}
771*0Sstevel@tonic-gate 		} else {
772*0Sstevel@tonic-gate 			free(ret);
773*0Sstevel@tonic-gate 			ret = strdup(path);
774*0Sstevel@tonic-gate 		}
775*0Sstevel@tonic-gate 	}
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	return (ret);
778*0Sstevel@tonic-gate }
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate /*ARGSUSED*/
782*0Sstevel@tonic-gate static char *
783*0Sstevel@tonic-gate _unix_crypt_gensalt(char *gsbuffer,
784*0Sstevel@tonic-gate 	    size_t gsbufflen,
785*0Sstevel@tonic-gate 	    const char *oldpuresalt,
786*0Sstevel@tonic-gate 	    const struct passwd *userinfo,
787*0Sstevel@tonic-gate 	    const char *argv[])
788*0Sstevel@tonic-gate {
789*0Sstevel@tonic-gate 	static const char saltchars[] =
790*0Sstevel@tonic-gate 	    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
791*0Sstevel@tonic-gate 	struct timeval tv;
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	gettimeofday(&tv, (void *) 0);
794*0Sstevel@tonic-gate 	srand48(tv.tv_sec ^ tv.tv_usec);
795*0Sstevel@tonic-gate 	gsbuffer[0] = saltchars[lrand48() % 64]; /* lrand48() is MT-SAFE */
796*0Sstevel@tonic-gate 	gsbuffer[1] = saltchars[lrand48() % 64]; /* lrand48() is MT-SAFE */
797*0Sstevel@tonic-gate 	gsbuffer[2] = '\0';
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate 	return (gsbuffer);
800*0Sstevel@tonic-gate }
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate /*
803*0Sstevel@tonic-gate  * The rest of the code below comes from the old crypt.c and is the
804*0Sstevel@tonic-gate  * implementation of the hardwired/fallback traditional algorithm
805*0Sstevel@tonic-gate  * It has been otimized to take better advantage of MT features.
806*0Sstevel@tonic-gate  *
807*0Sstevel@tonic-gate  * It is included here to reduce the overhead of dlopen()
808*0Sstevel@tonic-gate  * for the common case.
809*0Sstevel@tonic-gate  */
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
813*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate /*
818*0Sstevel@tonic-gate  * This program implements a data encryption algorithm to encrypt passwords.
819*0Sstevel@tonic-gate  */
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate static mutex_t crypt_lock = DEFAULTMUTEX;
822*0Sstevel@tonic-gate #define	TSDBUFSZ	(66 + 16)
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate static const char IP[] = {
825*0Sstevel@tonic-gate 	58, 50, 42, 34, 26, 18, 10, 2,
826*0Sstevel@tonic-gate 	60, 52, 44, 36, 28, 20, 12, 4,
827*0Sstevel@tonic-gate 	62, 54, 46, 38, 30, 22, 14, 6,
828*0Sstevel@tonic-gate 	64, 56, 48, 40, 32, 24, 16, 8,
829*0Sstevel@tonic-gate 	57, 49, 41, 33, 25, 17, 9, 1,
830*0Sstevel@tonic-gate 	59, 51, 43, 35, 27, 19, 11, 3,
831*0Sstevel@tonic-gate 	61, 53, 45, 37, 29, 21, 13, 5,
832*0Sstevel@tonic-gate 	63, 55, 47, 39, 31, 23, 15, 7,
833*0Sstevel@tonic-gate };
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate static const char FP[] = {
836*0Sstevel@tonic-gate 	40, 8, 48, 16, 56, 24, 64, 32,
837*0Sstevel@tonic-gate 	39, 7, 47, 15,  55, 23, 63, 31,
838*0Sstevel@tonic-gate 	38, 6, 46, 14, 54, 22, 62, 30,
839*0Sstevel@tonic-gate 	37, 5, 45, 13, 53, 21, 61, 29,
840*0Sstevel@tonic-gate 	36, 4, 44, 12, 52, 20, 60, 28,
841*0Sstevel@tonic-gate 	35, 3, 43, 11, 51, 19, 59, 27,
842*0Sstevel@tonic-gate 	34, 2, 42, 10, 50, 18, 58, 26,
843*0Sstevel@tonic-gate 	33, 1, 41, 9, 49, 17, 57, 25,
844*0Sstevel@tonic-gate };
845*0Sstevel@tonic-gate 
846*0Sstevel@tonic-gate static const char PC1_C[] = {
847*0Sstevel@tonic-gate 	57, 49, 41, 33, 25, 17, 9,
848*0Sstevel@tonic-gate 	1, 58, 50, 42, 34, 26, 18,
849*0Sstevel@tonic-gate 	10, 2, 59, 51, 43, 35, 27,
850*0Sstevel@tonic-gate 	19, 11, 3, 60, 52, 44, 36,
851*0Sstevel@tonic-gate };
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate static const char PC1_D[] = {
854*0Sstevel@tonic-gate 	63, 55, 47, 39, 31, 23, 15,
855*0Sstevel@tonic-gate 	7, 62, 54, 46, 38, 30, 22,
856*0Sstevel@tonic-gate 	14, 6, 61, 53, 45, 37, 29,
857*0Sstevel@tonic-gate 	21, 13, 5, 28, 20, 12, 4,
858*0Sstevel@tonic-gate };
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate static const char shifts[] = {
861*0Sstevel@tonic-gate 	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
862*0Sstevel@tonic-gate };
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate static const char PC2_C[] = {
865*0Sstevel@tonic-gate 	14, 17, 11, 24, 1, 5,
866*0Sstevel@tonic-gate 	3, 28, 15, 6, 21, 10,
867*0Sstevel@tonic-gate 	23, 19, 12, 4, 26, 8,
868*0Sstevel@tonic-gate 	16, 7, 27, 20, 13, 2,
869*0Sstevel@tonic-gate };
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate static const char PC2_D[] = {
872*0Sstevel@tonic-gate 	41, 52, 31, 37, 47, 55,
873*0Sstevel@tonic-gate 	30, 40, 51, 45, 33, 48,
874*0Sstevel@tonic-gate 	44, 49, 39, 56, 34, 53,
875*0Sstevel@tonic-gate 	46, 42, 50, 36, 29, 32,
876*0Sstevel@tonic-gate };
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate static char C[28];
879*0Sstevel@tonic-gate static char D[28];
880*0Sstevel@tonic-gate static char *KS;
881*0Sstevel@tonic-gate 
882*0Sstevel@tonic-gate static char E[48];
883*0Sstevel@tonic-gate static const char e2[] = {
884*0Sstevel@tonic-gate 	32, 1, 2, 3, 4, 5,
885*0Sstevel@tonic-gate 	4, 5, 6, 7, 8, 9,
886*0Sstevel@tonic-gate 	8, 9, 10, 11, 12, 13,
887*0Sstevel@tonic-gate 	12, 13, 14, 15, 16, 17,
888*0Sstevel@tonic-gate 	16, 17, 18, 19, 20, 21,
889*0Sstevel@tonic-gate 	20, 21, 22, 23, 24, 25,
890*0Sstevel@tonic-gate 	24, 25, 26, 27, 28, 29,
891*0Sstevel@tonic-gate 	28, 29, 30, 31, 32, 1,
892*0Sstevel@tonic-gate };
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate /*
895*0Sstevel@tonic-gate  * The KS array (768 bytes) is allocated once, and only if
896*0Sstevel@tonic-gate  * one of _unix_crypt(), encrypt() or setkey() is called.
897*0Sstevel@tonic-gate  * The complexity below is due to the fact that calloc()
898*0Sstevel@tonic-gate  * must not be called while holding any locks.
899*0Sstevel@tonic-gate  */
900*0Sstevel@tonic-gate static int
901*0Sstevel@tonic-gate allocate_KS(void)
902*0Sstevel@tonic-gate {
903*0Sstevel@tonic-gate 	char *ks;
904*0Sstevel@tonic-gate 	int failed;
905*0Sstevel@tonic-gate 	int assigned;
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 	if (KS != NULL)		/* already allocated */
908*0Sstevel@tonic-gate 		return (0);
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	ks = calloc(16, 48 * sizeof (char));
911*0Sstevel@tonic-gate 	failed = 0;
912*0Sstevel@tonic-gate 	lmutex_lock(&crypt_lock);
913*0Sstevel@tonic-gate 	if (KS != NULL) {	/* someone else got here first */
914*0Sstevel@tonic-gate 		assigned = 0;
915*0Sstevel@tonic-gate 	} else {
916*0Sstevel@tonic-gate 		assigned = 1;
917*0Sstevel@tonic-gate 		if ((KS = ks) == NULL)	/* calloc() failed */
918*0Sstevel@tonic-gate 			failed = 1;
919*0Sstevel@tonic-gate 	}
920*0Sstevel@tonic-gate 	lmutex_unlock(&crypt_lock);
921*0Sstevel@tonic-gate 	if (!assigned)
922*0Sstevel@tonic-gate 		free(ks);
923*0Sstevel@tonic-gate 	return (failed);
924*0Sstevel@tonic-gate }
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate static void
927*0Sstevel@tonic-gate unlocked_setkey(const char *key)
928*0Sstevel@tonic-gate {
929*0Sstevel@tonic-gate 	int i, j, k;
930*0Sstevel@tonic-gate 	char t;
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	for (i = 0; i < 28; i++) {
933*0Sstevel@tonic-gate 		C[i] = key[PC1_C[i]-1];
934*0Sstevel@tonic-gate 		D[i] = key[PC1_D[i]-1];
935*0Sstevel@tonic-gate 	}
936*0Sstevel@tonic-gate 	for (i = 0; i < 16; i++) {
937*0Sstevel@tonic-gate 		for (k = 0; k < shifts[i]; k++) {
938*0Sstevel@tonic-gate 			t = C[0];
939*0Sstevel@tonic-gate 			for (j = 0; j < 28-1; j++)
940*0Sstevel@tonic-gate 				C[j] = C[j+1];
941*0Sstevel@tonic-gate 			C[27] = t;
942*0Sstevel@tonic-gate 			t = D[0];
943*0Sstevel@tonic-gate 			for (j = 0; j < 28-1; j++)
944*0Sstevel@tonic-gate 				D[j] = D[j+1];
945*0Sstevel@tonic-gate 			D[27] = t;
946*0Sstevel@tonic-gate 		}
947*0Sstevel@tonic-gate 		for (j = 0; j < 24; j++) {
948*0Sstevel@tonic-gate 			int index = i * 48;
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 			*(KS+index+j) = C[PC2_C[j]-1];
951*0Sstevel@tonic-gate 			*(KS+index+j+24) = D[PC2_D[j]-28-1];
952*0Sstevel@tonic-gate 		}
953*0Sstevel@tonic-gate 	}
954*0Sstevel@tonic-gate 	for (i = 0; i < 48; i++)
955*0Sstevel@tonic-gate 		E[i] = e2[i];
956*0Sstevel@tonic-gate }
957*0Sstevel@tonic-gate 
958*0Sstevel@tonic-gate static const char S[8][64] = {
959*0Sstevel@tonic-gate 	14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
960*0Sstevel@tonic-gate 	0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
961*0Sstevel@tonic-gate 	4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
962*0Sstevel@tonic-gate 	15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
965*0Sstevel@tonic-gate 	3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
966*0Sstevel@tonic-gate 	0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
967*0Sstevel@tonic-gate 	13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
970*0Sstevel@tonic-gate 	13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
971*0Sstevel@tonic-gate 	13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
972*0Sstevel@tonic-gate 	1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
973*0Sstevel@tonic-gate 
974*0Sstevel@tonic-gate 	7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
975*0Sstevel@tonic-gate 	13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
976*0Sstevel@tonic-gate 	10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
977*0Sstevel@tonic-gate 	3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate 	2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
980*0Sstevel@tonic-gate 	14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
981*0Sstevel@tonic-gate 	4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
982*0Sstevel@tonic-gate 	11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
985*0Sstevel@tonic-gate 	10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
986*0Sstevel@tonic-gate 	9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
987*0Sstevel@tonic-gate 	4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate 	4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
990*0Sstevel@tonic-gate 	13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
991*0Sstevel@tonic-gate 	1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
992*0Sstevel@tonic-gate 	6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 	13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
995*0Sstevel@tonic-gate 	1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
996*0Sstevel@tonic-gate 	7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
997*0Sstevel@tonic-gate 	2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11,
998*0Sstevel@tonic-gate };
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate static const char P[] = {
1001*0Sstevel@tonic-gate 	16, 7, 20, 21,
1002*0Sstevel@tonic-gate 	29, 12, 28, 17,
1003*0Sstevel@tonic-gate 	1, 15, 23, 26,
1004*0Sstevel@tonic-gate 	5, 18, 31, 10,
1005*0Sstevel@tonic-gate 	2, 8, 24, 14,
1006*0Sstevel@tonic-gate 	32, 27, 3, 9,
1007*0Sstevel@tonic-gate 	19, 13, 30, 6,
1008*0Sstevel@tonic-gate 	22, 11, 4, 25,
1009*0Sstevel@tonic-gate };
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate static char L[64];
1012*0Sstevel@tonic-gate static char tempL[32];
1013*0Sstevel@tonic-gate static char f[32];
1014*0Sstevel@tonic-gate 
1015*0Sstevel@tonic-gate static char preS[48];
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate /*ARGSUSED*/
1018*0Sstevel@tonic-gate static void
1019*0Sstevel@tonic-gate unlocked_encrypt(char *block, int fake)
1020*0Sstevel@tonic-gate {
1021*0Sstevel@tonic-gate 	int	i;
1022*0Sstevel@tonic-gate 	int t, j, k;
1023*0Sstevel@tonic-gate 	char *R = &L[32];
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate 	for (j = 0; j < 64; j++)
1026*0Sstevel@tonic-gate 		L[j] = block[IP[j]-1];
1027*0Sstevel@tonic-gate 	for (i = 0; i < 16; i++) {
1028*0Sstevel@tonic-gate 		int index = i * 48;
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 		for (j = 0; j < 32; j++)
1031*0Sstevel@tonic-gate 			tempL[j] = R[j];
1032*0Sstevel@tonic-gate 		for (j = 0; j < 48; j++)
1033*0Sstevel@tonic-gate 			preS[j] = R[E[j]-1] ^ *(KS+index+j);
1034*0Sstevel@tonic-gate 		for (j = 0; j < 8; j++) {
1035*0Sstevel@tonic-gate 			t = 6 * j;
1036*0Sstevel@tonic-gate 			k = S[j][(preS[t+0]<<5)+
1037*0Sstevel@tonic-gate 				(preS[t+1]<<3)+
1038*0Sstevel@tonic-gate 				(preS[t+2]<<2)+
1039*0Sstevel@tonic-gate 				(preS[t+3]<<1)+
1040*0Sstevel@tonic-gate 				(preS[t+4]<<0)+
1041*0Sstevel@tonic-gate 				(preS[t+5]<<4)];
1042*0Sstevel@tonic-gate 			t = 4*j;
1043*0Sstevel@tonic-gate 			f[t+0] = (k>>3)&01;
1044*0Sstevel@tonic-gate 			f[t+1] = (k>>2)&01;
1045*0Sstevel@tonic-gate 			f[t+2] = (k>>1)&01;
1046*0Sstevel@tonic-gate 			f[t+3] = (k>>0)&01;
1047*0Sstevel@tonic-gate 		}
1048*0Sstevel@tonic-gate 		for (j = 0; j < 32; j++)
1049*0Sstevel@tonic-gate 			R[j] = L[j] ^ f[P[j]-1];
1050*0Sstevel@tonic-gate 		for (j = 0; j < 32; j++)
1051*0Sstevel@tonic-gate 			L[j] = tempL[j];
1052*0Sstevel@tonic-gate 	}
1053*0Sstevel@tonic-gate 	for (j = 0; j < 32; j++) {
1054*0Sstevel@tonic-gate 		t = L[j];
1055*0Sstevel@tonic-gate 		L[j] = R[j];
1056*0Sstevel@tonic-gate 		R[j] = (char)t;
1057*0Sstevel@tonic-gate 	}
1058*0Sstevel@tonic-gate 	for (j = 0; j < 64; j++)
1059*0Sstevel@tonic-gate 		block[j] = L[FP[j]-1];
1060*0Sstevel@tonic-gate }
1061*0Sstevel@tonic-gate 
1062*0Sstevel@tonic-gate char *
1063*0Sstevel@tonic-gate _unix_crypt(const char *pw, const char *salt, char *iobuf)
1064*0Sstevel@tonic-gate {
1065*0Sstevel@tonic-gate 	int c, i, j;
1066*0Sstevel@tonic-gate 	char temp;
1067*0Sstevel@tonic-gate 	char *block;
1068*0Sstevel@tonic-gate 
1069*0Sstevel@tonic-gate 	block = iobuf + 16;
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate 	if (iobuf == 0) {
1072*0Sstevel@tonic-gate 		errno = ENOMEM;
1073*0Sstevel@tonic-gate 		return (NULL);
1074*0Sstevel@tonic-gate 	}
1075*0Sstevel@tonic-gate 	if (allocate_KS() != 0)
1076*0Sstevel@tonic-gate 		return (NULL);
1077*0Sstevel@tonic-gate 	lmutex_lock(&crypt_lock);
1078*0Sstevel@tonic-gate 	for (i = 0; i < 66; i++)
1079*0Sstevel@tonic-gate 		block[i] = 0;
1080*0Sstevel@tonic-gate 	for (i = 0; (c = *pw) != '\0' && i < 64; pw++) {
1081*0Sstevel@tonic-gate 		for (j = 0; j < 7; j++, i++)
1082*0Sstevel@tonic-gate 			block[i] = (c>>(6-j)) & 01;
1083*0Sstevel@tonic-gate 		i++;
1084*0Sstevel@tonic-gate 	}
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate 	unlocked_setkey(block);
1087*0Sstevel@tonic-gate 
1088*0Sstevel@tonic-gate 	for (i = 0; i < 66; i++)
1089*0Sstevel@tonic-gate 		block[i] = 0;
1090*0Sstevel@tonic-gate 
1091*0Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
1092*0Sstevel@tonic-gate 		c = *salt++;
1093*0Sstevel@tonic-gate 		iobuf[i] = (char)c;
1094*0Sstevel@tonic-gate 		if (c > 'Z')
1095*0Sstevel@tonic-gate 			c -= 6;
1096*0Sstevel@tonic-gate 		if (c > '9')
1097*0Sstevel@tonic-gate 			c -= 7;
1098*0Sstevel@tonic-gate 		c -= '.';
1099*0Sstevel@tonic-gate 		for (j = 0; j < 6; j++) {
1100*0Sstevel@tonic-gate 			if ((c>>j) & 01) {
1101*0Sstevel@tonic-gate 				temp = E[6*i+j];
1102*0Sstevel@tonic-gate 				E[6*i+j] = E[6*i+j+24];
1103*0Sstevel@tonic-gate 				E[6*i+j+24] = temp;
1104*0Sstevel@tonic-gate 			}
1105*0Sstevel@tonic-gate 		}
1106*0Sstevel@tonic-gate 	}
1107*0Sstevel@tonic-gate 
1108*0Sstevel@tonic-gate 	for (i = 0; i < 25; i++)
1109*0Sstevel@tonic-gate 		unlocked_encrypt(block, 0);
1110*0Sstevel@tonic-gate 
1111*0Sstevel@tonic-gate 	lmutex_unlock(&crypt_lock);
1112*0Sstevel@tonic-gate 	for (i = 0; i < 11; i++) {
1113*0Sstevel@tonic-gate 		c = 0;
1114*0Sstevel@tonic-gate 		for (j = 0; j < 6; j++) {
1115*0Sstevel@tonic-gate 			c <<= 1;
1116*0Sstevel@tonic-gate 			c |= block[6*i+j];
1117*0Sstevel@tonic-gate 		}
1118*0Sstevel@tonic-gate 		c += '.';
1119*0Sstevel@tonic-gate 		if (c > '9')
1120*0Sstevel@tonic-gate 			c += 7;
1121*0Sstevel@tonic-gate 		if (c > 'Z')
1122*0Sstevel@tonic-gate 			c += 6;
1123*0Sstevel@tonic-gate 		iobuf[i+2] = (char)c;
1124*0Sstevel@tonic-gate 	}
1125*0Sstevel@tonic-gate 	iobuf[i+2] = 0;
1126*0Sstevel@tonic-gate 	if (iobuf[1] == 0)
1127*0Sstevel@tonic-gate 		iobuf[1] = iobuf[0];
1128*0Sstevel@tonic-gate 	return (iobuf);
1129*0Sstevel@tonic-gate }
1130*0Sstevel@tonic-gate 
1131*0Sstevel@tonic-gate 
1132*0Sstevel@tonic-gate /*ARGSUSED*/
1133*0Sstevel@tonic-gate void
1134*0Sstevel@tonic-gate encrypt(char *block, int fake)
1135*0Sstevel@tonic-gate {
1136*0Sstevel@tonic-gate 	if (fake != 0) {
1137*0Sstevel@tonic-gate 		errno = ENOSYS;
1138*0Sstevel@tonic-gate 		return;
1139*0Sstevel@tonic-gate 	}
1140*0Sstevel@tonic-gate 	if (allocate_KS() != 0)
1141*0Sstevel@tonic-gate 		return;
1142*0Sstevel@tonic-gate 	lmutex_lock(&crypt_lock);
1143*0Sstevel@tonic-gate 	unlocked_encrypt(block, fake);
1144*0Sstevel@tonic-gate 	lmutex_unlock(&crypt_lock);
1145*0Sstevel@tonic-gate }
1146*0Sstevel@tonic-gate 
1147*0Sstevel@tonic-gate 
1148*0Sstevel@tonic-gate void
1149*0Sstevel@tonic-gate setkey(const char *key)
1150*0Sstevel@tonic-gate {
1151*0Sstevel@tonic-gate 	if (allocate_KS() != 0)
1152*0Sstevel@tonic-gate 		return;
1153*0Sstevel@tonic-gate 	lmutex_lock(&crypt_lock);
1154*0Sstevel@tonic-gate 	unlocked_setkey(key);
1155*0Sstevel@tonic-gate 	lmutex_unlock(&crypt_lock);
1156*0Sstevel@tonic-gate }
1157