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