xref: /illumos-gate/usr/src/lib/libc/port/gen/crypt.c (revision 6e2462f93bf3de7b08885a4677464e11be3c807b)
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 	free(alg->a_params);
701 	free(alg);
702 }
703 
704 static void
705 free_crypt_policy(struct crypt_policy_s *policy)
706 {
707 	if (policy == NULL)
708 		return;
709 
710 	if (policy->cp_default != NULL) {
711 		bzero(policy->cp_default, strlen(policy->cp_default));
712 		free(policy->cp_default);
713 		policy->cp_default = NULL;
714 	}
715 
716 	if (policy->cp_allow != NULL) {
717 		bzero(policy->cp_allow, strlen(policy->cp_allow));
718 		free(policy->cp_allow);
719 		policy->cp_allow = NULL;
720 	}
721 
722 	if (policy->cp_deny != NULL) {
723 		bzero(policy->cp_deny, strlen(policy->cp_deny));
724 		free(policy->cp_deny);
725 		policy->cp_deny = NULL;
726 	}
727 
728 	free(policy);
729 }
730 
731 
732 /*
733  * isa_path - prepend the default dir or patch up the $ISA in path
734  *	Caller is responsible for calling free(3c) on the result.
735  */
736 static char *
737 isa_path(const char *path)
738 {
739 	char *ret = NULL;
740 
741 	if ((path == NULL) || (strlen(path) > PATH_MAX)) {
742 		return (NULL);
743 	}
744 
745 	ret = calloc(PATH_MAX, sizeof (char));
746 
747 	/*
748 	 * Module path doesn't start with "/" then prepend
749 	 * the default search path CRYPT_MODULE_DIR (/usr/lib/security/$ISA)
750 	 */
751 	if (path[0] != '/') {
752 		if (snprintf(ret, PATH_MAX, "%s%s", CRYPT_MODULE_DIR,
753 		    path) > PATH_MAX) {
754 			free(ret);
755 			return (NULL);
756 		}
757 	} else { /* patch up $ISA */
758 		char *isa;
759 
760 		if ((isa = strstr(path, CRYPT_MODULE_ISA)) != NULL) {
761 			*isa = '\0';
762 			isa += strlen(CRYPT_MODULE_ISA);
763 			if (snprintf(ret, PATH_MAX, "%s%s%s", path,
764 			    CRYPT_ISA_DIR, isa) > PATH_MAX) {
765 				free(ret);
766 				return (NULL);
767 			}
768 		} else {
769 			free(ret);
770 			ret = strdup(path);
771 		}
772 	}
773 
774 	return (ret);
775 }
776 
777 
778 /*ARGSUSED*/
779 static char *
780 _unix_crypt_gensalt(char *gsbuffer,
781     size_t gsbufflen,
782     const char *oldpuresalt,
783     const struct passwd *userinfo,
784     const char *argv[])
785 {
786 	static const char saltchars[] =
787 	    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
788 	struct timeval tv;
789 
790 	(void) gettimeofday(&tv, (void *) 0);
791 	srand48(tv.tv_sec ^ tv.tv_usec);
792 	gsbuffer[0] = saltchars[lrand48() % 64]; /* lrand48() is MT-SAFE */
793 	gsbuffer[1] = saltchars[lrand48() % 64]; /* lrand48() is MT-SAFE */
794 	gsbuffer[2] = '\0';
795 
796 	return (gsbuffer);
797 }
798 
799 /*
800  * The rest of the code below comes from the old crypt.c and is the
801  * implementation of the hardwired/fallback traditional algorithm
802  * It has been otimized to take better advantage of MT features.
803  *
804  * It is included here to reduce the overhead of dlopen()
805  * for the common case.
806  */
807 
808 
809 /*	Copyright (c) 1988 AT&T	*/
810 /*	  All Rights Reserved	*/
811 
812 
813 
814 /*
815  * This program implements a data encryption algorithm to encrypt passwords.
816  */
817 
818 static mutex_t crypt_lock = DEFAULTMUTEX;
819 #define	TSDBUFSZ	(66 + 16)
820 
821 static const char IP[] = {
822 	58, 50, 42, 34, 26, 18, 10, 2,
823 	60, 52, 44, 36, 28, 20, 12, 4,
824 	62, 54, 46, 38, 30, 22, 14, 6,
825 	64, 56, 48, 40, 32, 24, 16, 8,
826 	57, 49, 41, 33, 25, 17, 9, 1,
827 	59, 51, 43, 35, 27, 19, 11, 3,
828 	61, 53, 45, 37, 29, 21, 13, 5,
829 	63, 55, 47, 39, 31, 23, 15, 7,
830 };
831 
832 static const char FP[] = {
833 	40, 8, 48, 16, 56, 24, 64, 32,
834 	39, 7, 47, 15,  55, 23, 63, 31,
835 	38, 6, 46, 14, 54, 22, 62, 30,
836 	37, 5, 45, 13, 53, 21, 61, 29,
837 	36, 4, 44, 12, 52, 20, 60, 28,
838 	35, 3, 43, 11, 51, 19, 59, 27,
839 	34, 2, 42, 10, 50, 18, 58, 26,
840 	33, 1, 41, 9, 49, 17, 57, 25,
841 };
842 
843 static const char PC1_C[] = {
844 	57, 49, 41, 33, 25, 17, 9,
845 	1, 58, 50, 42, 34, 26, 18,
846 	10, 2, 59, 51, 43, 35, 27,
847 	19, 11, 3, 60, 52, 44, 36,
848 };
849 
850 static const char PC1_D[] = {
851 	63, 55, 47, 39, 31, 23, 15,
852 	7, 62, 54, 46, 38, 30, 22,
853 	14, 6, 61, 53, 45, 37, 29,
854 	21, 13, 5, 28, 20, 12, 4,
855 };
856 
857 static const char shifts[] = {
858 	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
859 };
860 
861 static const char PC2_C[] = {
862 	14, 17, 11, 24, 1, 5,
863 	3, 28, 15, 6, 21, 10,
864 	23, 19, 12, 4, 26, 8,
865 	16, 7, 27, 20, 13, 2,
866 };
867 
868 static const char PC2_D[] = {
869 	41, 52, 31, 37, 47, 55,
870 	30, 40, 51, 45, 33, 48,
871 	44, 49, 39, 56, 34, 53,
872 	46, 42, 50, 36, 29, 32,
873 };
874 
875 static char C[28];
876 static char D[28];
877 static char *KS;
878 
879 static char E[48];
880 static const char e2[] = {
881 	32, 1, 2, 3, 4, 5,
882 	4, 5, 6, 7, 8, 9,
883 	8, 9, 10, 11, 12, 13,
884 	12, 13, 14, 15, 16, 17,
885 	16, 17, 18, 19, 20, 21,
886 	20, 21, 22, 23, 24, 25,
887 	24, 25, 26, 27, 28, 29,
888 	28, 29, 30, 31, 32, 1,
889 };
890 
891 /*
892  * The KS array (768 bytes) is allocated once, and only if
893  * one of _unix_crypt(), encrypt() or setkey() is called.
894  * The complexity below is due to the fact that calloc()
895  * must not be called while holding any locks.
896  */
897 static int
898 allocate_KS(void)
899 {
900 	char *ks;
901 	int failed;
902 	int assigned;
903 
904 	if (KS != NULL) {		/* already allocated */
905 		membar_consumer();
906 		return (0);
907 	}
908 
909 	ks = calloc(16, 48 * sizeof (char));
910 	failed = 0;
911 	lmutex_lock(&crypt_lock);
912 	if (KS != NULL) {	/* someone else got here first */
913 		assigned = 0;
914 	} else {
915 		assigned = 1;
916 		membar_producer();
917 		if ((KS = ks) == NULL)	/* calloc() failed */
918 			failed = 1;
919 	}
920 	lmutex_unlock(&crypt_lock);
921 	if (!assigned)
922 		free(ks);
923 	return (failed);
924 }
925 
926 static void
927 unlocked_setkey(const char *key)
928 {
929 	int i, j, k;
930 	char t;
931 
932 	for (i = 0; i < 28; i++) {
933 		C[i] = key[PC1_C[i]-1];
934 		D[i] = key[PC1_D[i]-1];
935 	}
936 	for (i = 0; i < 16; i++) {
937 		for (k = 0; k < shifts[i]; k++) {
938 			t = C[0];
939 			for (j = 0; j < 28-1; j++)
940 				C[j] = C[j+1];
941 			C[27] = t;
942 			t = D[0];
943 			for (j = 0; j < 28-1; j++)
944 				D[j] = D[j+1];
945 			D[27] = t;
946 		}
947 		for (j = 0; j < 24; j++) {
948 			int index = i * 48;
949 
950 			*(KS+index+j) = C[PC2_C[j]-1];
951 			*(KS+index+j+24) = D[PC2_D[j]-28-1];
952 		}
953 	}
954 	for (i = 0; i < 48; i++)
955 		E[i] = e2[i];
956 }
957 
958 static const char S[8][64] = {
959 	14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
960 	0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
961 	4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
962 	15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
963 
964 	15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
965 	3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
966 	0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
967 	13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
968 
969 	10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
970 	13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
971 	13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
972 	1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
973 
974 	7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
975 	13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
976 	10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
977 	3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
978 
979 	2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
980 	14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
981 	4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
982 	11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
983 
984 	12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
985 	10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
986 	9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
987 	4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
988 
989 	4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
990 	13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
991 	1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
992 	6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
993 
994 	13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
995 	1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
996 	7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
997 	2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11,
998 };
999 
1000 static const char P[] = {
1001 	16, 7, 20, 21,
1002 	29, 12, 28, 17,
1003 	1, 15, 23, 26,
1004 	5, 18, 31, 10,
1005 	2, 8, 24, 14,
1006 	32, 27, 3, 9,
1007 	19, 13, 30, 6,
1008 	22, 11, 4, 25,
1009 };
1010 
1011 static char L[64];
1012 static char tempL[32];
1013 static char f[32];
1014 
1015 static char preS[48];
1016 
1017 /*ARGSUSED*/
1018 static void
1019 unlocked_encrypt(char *block, int fake)
1020 {
1021 	int	i;
1022 	int t, j, k;
1023 	char *R = &L[32];
1024 
1025 	for (j = 0; j < 64; j++)
1026 		L[j] = block[IP[j]-1];
1027 	for (i = 0; i < 16; i++) {
1028 		int index = i * 48;
1029 
1030 		for (j = 0; j < 32; j++)
1031 			tempL[j] = R[j];
1032 		for (j = 0; j < 48; j++)
1033 			preS[j] = R[E[j]-1] ^ *(KS+index+j);
1034 		for (j = 0; j < 8; j++) {
1035 			t = 6 * j;
1036 			k = S[j][(preS[t+0]<<5) +
1037 			    (preS[t+1]<<3) +
1038 			    (preS[t+2]<<2) +
1039 			    (preS[t+3]<<1) +
1040 			    (preS[t+4]<<0) +
1041 			    (preS[t+5]<<4)];
1042 			t = 4*j;
1043 			f[t+0] = (k>>3)&01;
1044 			f[t+1] = (k>>2)&01;
1045 			f[t+2] = (k>>1)&01;
1046 			f[t+3] = (k>>0)&01;
1047 		}
1048 		for (j = 0; j < 32; j++)
1049 			R[j] = L[j] ^ f[P[j]-1];
1050 		for (j = 0; j < 32; j++)
1051 			L[j] = tempL[j];
1052 	}
1053 	for (j = 0; j < 32; j++) {
1054 		t = L[j];
1055 		L[j] = R[j];
1056 		R[j] = (char)t;
1057 	}
1058 	for (j = 0; j < 64; j++)
1059 		block[j] = L[FP[j]-1];
1060 }
1061 
1062 char *
1063 _unix_crypt(const char *pw, const char *salt, char *iobuf)
1064 {
1065 	int c, i, j;
1066 	char temp;
1067 	char *block;
1068 
1069 	block = iobuf + 16;
1070 
1071 	if (iobuf == 0) {
1072 		errno = ENOMEM;
1073 		return (NULL);
1074 	}
1075 	if (allocate_KS() != 0)
1076 		return (NULL);
1077 	lmutex_lock(&crypt_lock);
1078 	for (i = 0; i < 66; i++)
1079 		block[i] = 0;
1080 	for (i = 0; (c = *pw) != '\0' && i < 64; pw++) {
1081 		for (j = 0; j < 7; j++, i++)
1082 			block[i] = (c>>(6-j)) & 01;
1083 		i++;
1084 	}
1085 
1086 	unlocked_setkey(block);
1087 
1088 	for (i = 0; i < 66; i++)
1089 		block[i] = 0;
1090 
1091 	for (i = 0; i < 2; i++) {
1092 		c = *salt++;
1093 		iobuf[i] = (char)c;
1094 		if (c > 'Z')
1095 			c -= 6;
1096 		if (c > '9')
1097 			c -= 7;
1098 		c -= '.';
1099 		for (j = 0; j < 6; j++) {
1100 			if ((c>>j) & 01) {
1101 				temp = E[6*i+j];
1102 				E[6*i+j] = E[6*i+j+24];
1103 				E[6*i+j+24] = temp;
1104 			}
1105 		}
1106 	}
1107 
1108 	for (i = 0; i < 25; i++)
1109 		unlocked_encrypt(block, 0);
1110 
1111 	lmutex_unlock(&crypt_lock);
1112 	for (i = 0; i < 11; i++) {
1113 		c = 0;
1114 		for (j = 0; j < 6; j++) {
1115 			c <<= 1;
1116 			c |= block[6*i+j];
1117 		}
1118 		c += '.';
1119 		if (c > '9')
1120 			c += 7;
1121 		if (c > 'Z')
1122 			c += 6;
1123 		iobuf[i+2] = (char)c;
1124 	}
1125 	iobuf[i+2] = 0;
1126 	if (iobuf[1] == 0)
1127 		iobuf[1] = iobuf[0];
1128 	return (iobuf);
1129 }
1130 
1131 
1132 /*ARGSUSED*/
1133 void
1134 encrypt(char *block, int fake)
1135 {
1136 	if (fake != 0) {
1137 		errno = ENOSYS;
1138 		return;
1139 	}
1140 	if (allocate_KS() != 0)
1141 		return;
1142 	lmutex_lock(&crypt_lock);
1143 	unlocked_encrypt(block, fake);
1144 	lmutex_unlock(&crypt_lock);
1145 }
1146 
1147 
1148 void
1149 setkey(const char *key)
1150 {
1151 	if (allocate_KS() != 0)
1152 		return;
1153 	lmutex_lock(&crypt_lock);
1154 	unlocked_setkey(key);
1155 	lmutex_unlock(&crypt_lock);
1156 }
1157