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