17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5004388ebScasper * Common Development and Distribution License (the "License").
6004388ebScasper * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21cb620785Sraf
227c478bd9Sstevel@tonic-gate /*
23*5ad42b1bSSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277257d1b4Sraf #pragma weak _crypt = crypt
287257d1b4Sraf #pragma weak _encrypt = encrypt
297257d1b4Sraf #pragma weak _setkey = setkey
307c478bd9Sstevel@tonic-gate
317257d1b4Sraf #include "lint.h"
327c478bd9Sstevel@tonic-gate #include "mtlib.h"
337c478bd9Sstevel@tonic-gate #include <synch.h>
347c478bd9Sstevel@tonic-gate #include <thread.h>
357c478bd9Sstevel@tonic-gate #include <ctype.h>
367c478bd9Sstevel@tonic-gate #include <dlfcn.h>
377c478bd9Sstevel@tonic-gate #include <errno.h>
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <strings.h>
407c478bd9Sstevel@tonic-gate #include <stdlib.h>
417c478bd9Sstevel@tonic-gate #include <sys/time.h>
427c478bd9Sstevel@tonic-gate #include <limits.h>
437c478bd9Sstevel@tonic-gate #include <sys/types.h>
447c478bd9Sstevel@tonic-gate #include <sys/stat.h>
457c478bd9Sstevel@tonic-gate #include <fcntl.h>
467c478bd9Sstevel@tonic-gate #include <syslog.h>
477c478bd9Sstevel@tonic-gate #include <unistd.h>
48cb620785Sraf #include <atomic.h>
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate #include <crypt.h>
517c478bd9Sstevel@tonic-gate #include <libc.h>
527c478bd9Sstevel@tonic-gate #include "tsd.h"
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate #define CRYPT_ALGORITHMS_ALLOW "CRYPT_ALGORITHMS_ALLOW"
557c478bd9Sstevel@tonic-gate #define CRYPT_ALGORITHMS_DEPRECATE "CRYPT_ALGORITHMS_DEPRECATE"
567c478bd9Sstevel@tonic-gate #define CRYPT_DEFAULT "CRYPT_DEFAULT"
577c478bd9Sstevel@tonic-gate #define CRYPT_UNIX "__unix__"
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #define CRYPT_CONFFILE "/etc/security/crypt.conf"
607c478bd9Sstevel@tonic-gate #define POLICY_CONF_FILE "/etc/security/policy.conf"
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate #define CRYPT_CONFLINELENGTH 1024
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate #define CRYPT_MODULE_ISA "/$ISA/"
657c478bd9Sstevel@tonic-gate #ifdef _LP64
667c478bd9Sstevel@tonic-gate #define CRYPT_MODULE_DIR "/usr/lib/security/64/"
677c478bd9Sstevel@tonic-gate #define CRYPT_ISA_DIR "/64/"
687c478bd9Sstevel@tonic-gate #else /* !_LP64 */
697c478bd9Sstevel@tonic-gate #define CRYPT_MODULE_DIR "/usr/lib/security/"
707c478bd9Sstevel@tonic-gate #define CRYPT_ISA_DIR "/"
717c478bd9Sstevel@tonic-gate #endif /* _LP64 */
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate * MAX_ALGNAME_LEN:
757c478bd9Sstevel@tonic-gate *
767c478bd9Sstevel@tonic-gate * In practical terms this is probably never any bigger than about 10, but...
777c478bd9Sstevel@tonic-gate *
787c478bd9Sstevel@tonic-gate * It has to fix the encrypted password filed of struct spwd it is
797c478bd9Sstevel@tonic-gate * theoretically the maximum length of the cipher minus the magic $ sign.
807c478bd9Sstevel@tonic-gate * Though that would be unexpected.
817c478bd9Sstevel@tonic-gate * Since it also has to fit in crypt.conf it is CRYPT_CONFLINELENGTH
827c478bd9Sstevel@tonic-gate * minus the path to the module and the minimum white space.
837c478bd9Sstevel@tonic-gate *
847c478bd9Sstevel@tonic-gate * CRYPT_MAXCIPHERTEXTLEN is defined in crypt.h and is smaller than
857c478bd9Sstevel@tonic-gate * CRYPT_CONFLINELENGTH, and probably always will be.
867c478bd9Sstevel@tonic-gate */
877c478bd9Sstevel@tonic-gate #define MAX_ALGNAME_LEN (CRYPT_MAXCIPHERTEXTLEN - 1)
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate struct crypt_alg_s {
907c478bd9Sstevel@tonic-gate void *a_libhandle;
917c478bd9Sstevel@tonic-gate char *(*a_genhash)(char *, const size_t, const char *,
927c478bd9Sstevel@tonic-gate const char *, const char **);
937c478bd9Sstevel@tonic-gate char *(*a_gensalt)(char *, const size_t,
947c478bd9Sstevel@tonic-gate const char *, const struct passwd *, const char **);
957c478bd9Sstevel@tonic-gate char **a_params;
967c478bd9Sstevel@tonic-gate int a_nparams;
977c478bd9Sstevel@tonic-gate };
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate struct crypt_policy_s {
1007c478bd9Sstevel@tonic-gate char *cp_default;
1017c478bd9Sstevel@tonic-gate char *cp_allow;
1027c478bd9Sstevel@tonic-gate char *cp_deny;
1037c478bd9Sstevel@tonic-gate };
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate enum crypt_policy_error_e {
1067c478bd9Sstevel@tonic-gate CPE_BOTH = 1,
1077c478bd9Sstevel@tonic-gate CPE_MULTI
1087c478bd9Sstevel@tonic-gate };
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate static struct crypt_policy_s *getcryptpolicy(void);
1117c478bd9Sstevel@tonic-gate static void free_crypt_policy(struct crypt_policy_s *policy);
1127c478bd9Sstevel@tonic-gate static struct crypt_alg_s *getalgbyname(const char *algname, boolean_t *found);
1137c478bd9Sstevel@tonic-gate static void free_crypt_alg(struct crypt_alg_s *alg);
1147c478bd9Sstevel@tonic-gate static char *getalgfromsalt(const char *salt);
1157c478bd9Sstevel@tonic-gate static boolean_t alg_valid(const char *algname,
1167c478bd9Sstevel@tonic-gate const struct crypt_policy_s *policy);
1177c478bd9Sstevel@tonic-gate static char *isa_path(const char *path);
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate static char *_unix_crypt(const char *pw, const char *salt, char *iobuf);
1207c478bd9Sstevel@tonic-gate static char *_unix_crypt_gensalt(char *gsbuffer, size_t gsbufflen,
1217c478bd9Sstevel@tonic-gate const char *oldpuresalt, const struct passwd *userinfo,
1227c478bd9Sstevel@tonic-gate const char *params[]);
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate * crypt - string encoding function
1277c478bd9Sstevel@tonic-gate *
1287c478bd9Sstevel@tonic-gate * This function encodes strings in a suitable for for secure storage
1297c478bd9Sstevel@tonic-gate * as passwords. It generates the password hash given the plaintext and salt.
1307c478bd9Sstevel@tonic-gate *
1317c478bd9Sstevel@tonic-gate * If the first character of salt is "$" then we use crypt.conf(4) to
1327c478bd9Sstevel@tonic-gate * determine which plugin to use and run the crypt_genhash_impl(3c) function
1337c478bd9Sstevel@tonic-gate * from it.
1347c478bd9Sstevel@tonic-gate * Otherwise we use the old unix algorithm.
1357c478bd9Sstevel@tonic-gate *
1367c478bd9Sstevel@tonic-gate * RETURN VALUES
1377c478bd9Sstevel@tonic-gate * On Success we return a pointer to the encoded string. The
1387c478bd9Sstevel@tonic-gate * return value points to thread specific static data and should NOT
1397c478bd9Sstevel@tonic-gate * be passed free(3c).
1407c478bd9Sstevel@tonic-gate * On failure we return NULL and set errno to one of:
1417c478bd9Sstevel@tonic-gate * EINVAL, ELIBACC, ENOMEM, ENOSYS.
1427c478bd9Sstevel@tonic-gate */
1437c478bd9Sstevel@tonic-gate char *
crypt(const char * plaintext,const char * salt)1447c478bd9Sstevel@tonic-gate crypt(const char *plaintext, const char *salt)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate struct crypt_alg_s *alg;
1477c478bd9Sstevel@tonic-gate char *ctbuffer;
1487c478bd9Sstevel@tonic-gate char *ciphertext;
1497c478bd9Sstevel@tonic-gate char *algname;
1507c478bd9Sstevel@tonic-gate boolean_t found;
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate ctbuffer = tsdalloc(_T_CRYPT, CRYPT_MAXCIPHERTEXTLEN, NULL);
1537c478bd9Sstevel@tonic-gate if (ctbuffer == NULL)
1547c478bd9Sstevel@tonic-gate return (NULL);
1557c478bd9Sstevel@tonic-gate bzero(ctbuffer, CRYPT_MAXCIPHERTEXTLEN);
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate /*
1587c478bd9Sstevel@tonic-gate * '$' is never a possible salt char with the traditional unix
1597c478bd9Sstevel@tonic-gate * algorithm. If the salt passed in is NULL or the first char
1607c478bd9Sstevel@tonic-gate * of the salt isn't a $ then do the traditional thing.
1617c478bd9Sstevel@tonic-gate * We also do the traditional thing if the salt is only 1 char.
1627c478bd9Sstevel@tonic-gate */
1637c478bd9Sstevel@tonic-gate if (salt == NULL || salt[0] != '$' || strlen(salt) == 1) {
1647c478bd9Sstevel@tonic-gate return (_unix_crypt(plaintext, salt, ctbuffer));
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate * Find the algorithm name from the salt and look it up in
1697c478bd9Sstevel@tonic-gate * crypt.conf(4) to find out what shared object to use.
1707c478bd9Sstevel@tonic-gate * If we can't find it in crypt.conf then getalgbyname would
1717c478bd9Sstevel@tonic-gate * have returned with found = B_FALSE so we use the unix algorithm.
1727c478bd9Sstevel@tonic-gate * If alg is NULL but found = B_TRUE then there is a problem with
1737c478bd9Sstevel@tonic-gate * the plugin so we fail leaving errno set to what getalgbyname()
1747c478bd9Sstevel@tonic-gate * set it to or EINVAL it if wasn't set.
1757c478bd9Sstevel@tonic-gate */
1767c478bd9Sstevel@tonic-gate if ((algname = getalgfromsalt(salt)) == NULL) {
1777c478bd9Sstevel@tonic-gate return (NULL);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate errno = 0;
1817c478bd9Sstevel@tonic-gate alg = getalgbyname(algname, &found);
1827c478bd9Sstevel@tonic-gate if ((alg == NULL) || !found) {
1837c478bd9Sstevel@tonic-gate if (errno == 0)
1847c478bd9Sstevel@tonic-gate errno = EINVAL;
1857c478bd9Sstevel@tonic-gate ciphertext = NULL;
1867c478bd9Sstevel@tonic-gate goto cleanup;
1877c478bd9Sstevel@tonic-gate } else if (!found) {
1887c478bd9Sstevel@tonic-gate ciphertext = _unix_crypt(plaintext, salt, ctbuffer);
1897c478bd9Sstevel@tonic-gate } else {
1907c478bd9Sstevel@tonic-gate ciphertext = alg->a_genhash(ctbuffer, CRYPT_MAXCIPHERTEXTLEN,
1917c478bd9Sstevel@tonic-gate plaintext, salt, (const char **)alg->a_params);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate cleanup:
1957c478bd9Sstevel@tonic-gate free_crypt_alg(alg);
1967c478bd9Sstevel@tonic-gate if (algname != NULL)
1977c478bd9Sstevel@tonic-gate free(algname);
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate return (ciphertext);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate * crypt_gensalt - generate salt string for string encoding
2047c478bd9Sstevel@tonic-gate *
2057c478bd9Sstevel@tonic-gate * This function generates the salt string pased to crypt(3c).
2067c478bd9Sstevel@tonic-gate * If oldsalt is NULL, the use the default algorithm.
2077c478bd9Sstevel@tonic-gate * Other wise check the policy in policy.conf to ensure that it is
2087c478bd9Sstevel@tonic-gate * either still allowed or not deprecated.
2097c478bd9Sstevel@tonic-gate *
2107c478bd9Sstevel@tonic-gate * RETURN VALUES
2117c478bd9Sstevel@tonic-gate * Return a pointer to the new salt, the caller is responsible
2127c478bd9Sstevel@tonic-gate * for using free(3c) on the return value.
2137c478bd9Sstevel@tonic-gate * Returns NULL on error and sets errno to one of:
2147c478bd9Sstevel@tonic-gate * EINVAL, ELIBACC, ENOMEM
2157c478bd9Sstevel@tonic-gate */
2167c478bd9Sstevel@tonic-gate char *
crypt_gensalt(const char * oldsalt,const struct passwd * userinfo)2177c478bd9Sstevel@tonic-gate crypt_gensalt(const char *oldsalt, const struct passwd *userinfo)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate struct crypt_alg_s *alg = NULL;
2207c478bd9Sstevel@tonic-gate struct crypt_policy_s *policy = NULL;
2217c478bd9Sstevel@tonic-gate char *newsalt = NULL;
2227c478bd9Sstevel@tonic-gate char *gsbuffer;
2237c478bd9Sstevel@tonic-gate char *algname = NULL;
2247c478bd9Sstevel@tonic-gate boolean_t found;
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate gsbuffer = calloc(CRYPT_MAXCIPHERTEXTLEN, sizeof (char *));
2277c478bd9Sstevel@tonic-gate if (gsbuffer == NULL) {
2287c478bd9Sstevel@tonic-gate errno = ENOMEM;
2297c478bd9Sstevel@tonic-gate goto cleanup;
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate policy = getcryptpolicy();
2337c478bd9Sstevel@tonic-gate if (policy == NULL) {
2347c478bd9Sstevel@tonic-gate errno = EINVAL;
2357c478bd9Sstevel@tonic-gate goto cleanup;
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate algname = getalgfromsalt(oldsalt);
2397c478bd9Sstevel@tonic-gate if (!alg_valid(algname, policy)) {
2407c478bd9Sstevel@tonic-gate free(algname);
2417c478bd9Sstevel@tonic-gate algname = strdup(policy->cp_default);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate if (strcmp(algname, CRYPT_UNIX) == 0) {
2457c478bd9Sstevel@tonic-gate newsalt = _unix_crypt_gensalt(gsbuffer, CRYPT_MAXCIPHERTEXTLEN,
2467c478bd9Sstevel@tonic-gate oldsalt, userinfo, NULL);
2477c478bd9Sstevel@tonic-gate } else {
2487c478bd9Sstevel@tonic-gate errno = 0;
2497c478bd9Sstevel@tonic-gate alg = getalgbyname(algname, &found);
2507c478bd9Sstevel@tonic-gate if (alg == NULL || !found) {
2517c478bd9Sstevel@tonic-gate if (errno == 0)
2527c478bd9Sstevel@tonic-gate errno = EINVAL;
2537c478bd9Sstevel@tonic-gate goto cleanup;
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate newsalt = alg->a_gensalt(gsbuffer, CRYPT_MAXCIPHERTEXTLEN,
2567c478bd9Sstevel@tonic-gate oldsalt, userinfo, (const char **)alg->a_params);
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate cleanup:
2607c478bd9Sstevel@tonic-gate free_crypt_policy(policy);
2617c478bd9Sstevel@tonic-gate free_crypt_alg(alg);
2627c478bd9Sstevel@tonic-gate if (newsalt == NULL && gsbuffer != NULL)
2637c478bd9Sstevel@tonic-gate free(gsbuffer);
2647c478bd9Sstevel@tonic-gate if (algname != NULL)
2657c478bd9Sstevel@tonic-gate free(algname);
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate return (newsalt);
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate /*
2717c478bd9Sstevel@tonic-gate * ===========================================================================
2727c478bd9Sstevel@tonic-gate * The remainder of this file contains internal interfaces for
2737c478bd9Sstevel@tonic-gate * the implementation of crypt(3c) and crypt_gensalt(3c)
2747c478bd9Sstevel@tonic-gate * ===========================================================================
2757c478bd9Sstevel@tonic-gate */
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate /*
2797c478bd9Sstevel@tonic-gate * getalgfromsalt - extract the algorithm name from the salt string
2807c478bd9Sstevel@tonic-gate */
2817c478bd9Sstevel@tonic-gate static char *
getalgfromsalt(const char * salt)2827c478bd9Sstevel@tonic-gate getalgfromsalt(const char *salt)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate char algname[CRYPT_MAXCIPHERTEXTLEN];
2857c478bd9Sstevel@tonic-gate int i;
2867c478bd9Sstevel@tonic-gate int j;
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate if (salt == NULL || strlen(salt) > CRYPT_MAXCIPHERTEXTLEN)
2897c478bd9Sstevel@tonic-gate return (NULL);
2907c478bd9Sstevel@tonic-gate /*
2917c478bd9Sstevel@tonic-gate * Salts are in this format:
2927c478bd9Sstevel@tonic-gate * $<algname>[,var=val,[var=val ...][$puresalt]$<ciphertext>
2937c478bd9Sstevel@tonic-gate *
2947c478bd9Sstevel@tonic-gate * The only bit we need to worry about here is extracting the
2957c478bd9Sstevel@tonic-gate * name which is the string between the first "$" and the first
2967c478bd9Sstevel@tonic-gate * of "," or second "$".
2977c478bd9Sstevel@tonic-gate */
2987c478bd9Sstevel@tonic-gate if (salt[0] != '$') {
2997c478bd9Sstevel@tonic-gate return (strdup(CRYPT_UNIX));
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate i = 1;
3037c478bd9Sstevel@tonic-gate j = 0;
3047c478bd9Sstevel@tonic-gate while (salt[i] != '\0' && salt[i] != '$' && salt[i] != ',') {
3057c478bd9Sstevel@tonic-gate algname[j] = salt[i];
3067c478bd9Sstevel@tonic-gate i++;
3077c478bd9Sstevel@tonic-gate j++;
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate if (j == 0)
3107c478bd9Sstevel@tonic-gate return (NULL);
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate algname[j] = '\0';
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate return (strdup(algname));
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate /*
3197c478bd9Sstevel@tonic-gate * log_invalid_policy - syslog helper
3207c478bd9Sstevel@tonic-gate */
3217c478bd9Sstevel@tonic-gate static void
log_invalid_policy(enum crypt_policy_error_e error,char * value)3227c478bd9Sstevel@tonic-gate log_invalid_policy(enum crypt_policy_error_e error, char *value)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate switch (error) {
3257c478bd9Sstevel@tonic-gate case CPE_BOTH:
3267c478bd9Sstevel@tonic-gate syslog(LOG_AUTH | LOG_ERR,
3277c478bd9Sstevel@tonic-gate "crypt(3c): %s contains both %s and %s; only one may be "
3287c478bd9Sstevel@tonic-gate "specified, using first entry in file.", POLICY_CONF_FILE,
3297c478bd9Sstevel@tonic-gate CRYPT_ALGORITHMS_ALLOW, CRYPT_ALGORITHMS_DEPRECATE);
3307c478bd9Sstevel@tonic-gate break;
3317c478bd9Sstevel@tonic-gate case CPE_MULTI:
3327c478bd9Sstevel@tonic-gate syslog(LOG_AUTH | LOG_ERR,
3337c478bd9Sstevel@tonic-gate "crypt(3c): %s contains multiple %s entries;"
3347c478bd9Sstevel@tonic-gate "using first entry file.", POLICY_CONF_FILE, value);
3357c478bd9Sstevel@tonic-gate break;
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate static char *
getval(const char * ival)3407c478bd9Sstevel@tonic-gate getval(const char *ival)
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate char *tmp;
3437c478bd9Sstevel@tonic-gate char *oval;
3447c478bd9Sstevel@tonic-gate int off;
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate if (ival == NULL)
3477c478bd9Sstevel@tonic-gate return (NULL);
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate if ((tmp = strchr(ival, '=')) == NULL)
3507c478bd9Sstevel@tonic-gate return (NULL);
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate oval = strdup(tmp + 1); /* everything after the "=" */
3537c478bd9Sstevel@tonic-gate if (oval == NULL)
3547c478bd9Sstevel@tonic-gate return (NULL);
3557c478bd9Sstevel@tonic-gate off = strlen(oval) - 1;
3567c478bd9Sstevel@tonic-gate if (off < 0) {
3577c478bd9Sstevel@tonic-gate free(oval);
3587c478bd9Sstevel@tonic-gate return (NULL);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate if (oval[off] == '\n')
3617c478bd9Sstevel@tonic-gate oval[off] = '\0';
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate return (oval);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate * getcryptpolicy - read /etc/security/policy.conf into a crypt_policy_s
3687c478bd9Sstevel@tonic-gate */
3697c478bd9Sstevel@tonic-gate static struct crypt_policy_s *
getcryptpolicy(void)3707c478bd9Sstevel@tonic-gate getcryptpolicy(void)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate FILE *pconf;
3737c478bd9Sstevel@tonic-gate char line[BUFSIZ];
3747c478bd9Sstevel@tonic-gate struct crypt_policy_s *policy;
3757c478bd9Sstevel@tonic-gate
376004388ebScasper if ((pconf = fopen(POLICY_CONF_FILE, "rF")) == NULL) {
3777c478bd9Sstevel@tonic-gate return (NULL);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate policy = malloc(sizeof (struct crypt_policy_s));
3817c478bd9Sstevel@tonic-gate if (policy == NULL) {
3827c478bd9Sstevel@tonic-gate return (NULL);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate policy->cp_default = NULL;
3857c478bd9Sstevel@tonic-gate policy->cp_allow = NULL;
3867c478bd9Sstevel@tonic-gate policy->cp_deny = NULL;
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate while (!feof(pconf) &&
3897c478bd9Sstevel@tonic-gate (fgets(line, sizeof (line), pconf) != NULL)) {
3907c478bd9Sstevel@tonic-gate if (strncasecmp(CRYPT_DEFAULT, line,
3917c478bd9Sstevel@tonic-gate strlen(CRYPT_DEFAULT)) == 0) {
3927c478bd9Sstevel@tonic-gate if (policy->cp_default != NULL) {
3937c478bd9Sstevel@tonic-gate log_invalid_policy(CPE_MULTI, CRYPT_DEFAULT);
3947c478bd9Sstevel@tonic-gate } else {
3957c478bd9Sstevel@tonic-gate policy->cp_default = getval(line);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate if (strncasecmp(CRYPT_ALGORITHMS_ALLOW, line,
3997c478bd9Sstevel@tonic-gate strlen(CRYPT_ALGORITHMS_ALLOW)) == 0) {
4007c478bd9Sstevel@tonic-gate if (policy->cp_deny != NULL) {
4017c478bd9Sstevel@tonic-gate log_invalid_policy(CPE_BOTH, NULL);
4027c478bd9Sstevel@tonic-gate } else if (policy->cp_allow != NULL) {
4037c478bd9Sstevel@tonic-gate log_invalid_policy(CPE_MULTI,
4047c478bd9Sstevel@tonic-gate CRYPT_ALGORITHMS_ALLOW);
4057c478bd9Sstevel@tonic-gate } else {
4067c478bd9Sstevel@tonic-gate policy->cp_allow = getval(line);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate if (strncasecmp(CRYPT_ALGORITHMS_DEPRECATE, line,
4107c478bd9Sstevel@tonic-gate strlen(CRYPT_ALGORITHMS_DEPRECATE)) == 0) {
4117c478bd9Sstevel@tonic-gate if (policy->cp_allow != NULL) {
4127c478bd9Sstevel@tonic-gate log_invalid_policy(CPE_BOTH, NULL);
4137c478bd9Sstevel@tonic-gate } else if (policy->cp_deny != NULL) {
4147c478bd9Sstevel@tonic-gate log_invalid_policy(CPE_MULTI,
4157c478bd9Sstevel@tonic-gate CRYPT_ALGORITHMS_DEPRECATE);
4167c478bd9Sstevel@tonic-gate } else {
4177c478bd9Sstevel@tonic-gate policy->cp_deny = getval(line);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate (void) fclose(pconf);
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate if (policy->cp_default == NULL) {
4247c478bd9Sstevel@tonic-gate policy->cp_default = strdup(CRYPT_UNIX);
4257c478bd9Sstevel@tonic-gate if (policy->cp_default == NULL)
4267c478bd9Sstevel@tonic-gate free_crypt_policy(policy);
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate return (policy);
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate /*
4347c478bd9Sstevel@tonic-gate * alg_valid - is this algorithm valid given the policy ?
4357c478bd9Sstevel@tonic-gate */
4367c478bd9Sstevel@tonic-gate static boolean_t
alg_valid(const char * algname,const struct crypt_policy_s * policy)4377c478bd9Sstevel@tonic-gate alg_valid(const char *algname, const struct crypt_policy_s *policy)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate char *lasts;
4407c478bd9Sstevel@tonic-gate char *list;
4417c478bd9Sstevel@tonic-gate char *entry;
4427c478bd9Sstevel@tonic-gate boolean_t allowed = B_FALSE;
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate if ((algname == NULL) || (policy == NULL)) {
4457c478bd9Sstevel@tonic-gate return (B_FALSE);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate if (strcmp(algname, policy->cp_default) == 0) {
4497c478bd9Sstevel@tonic-gate return (B_TRUE);
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate if (policy->cp_deny != NULL) {
4537c478bd9Sstevel@tonic-gate list = policy->cp_deny;
4547c478bd9Sstevel@tonic-gate allowed = B_FALSE;
4557c478bd9Sstevel@tonic-gate } else if (policy->cp_allow != NULL) {
4567c478bd9Sstevel@tonic-gate list = policy->cp_allow;
4577c478bd9Sstevel@tonic-gate allowed = B_TRUE;
4587c478bd9Sstevel@tonic-gate } else {
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate * Neither of allow or deny policies are set so anything goes.
4617c478bd9Sstevel@tonic-gate */
4627c478bd9Sstevel@tonic-gate return (B_TRUE);
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate lasts = list;
4657c478bd9Sstevel@tonic-gate while ((entry = strtok_r(NULL, ",", &lasts)) != NULL) {
4667c478bd9Sstevel@tonic-gate if (strcmp(entry, algname) == 0) {
4677c478bd9Sstevel@tonic-gate return (allowed);
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate return (!allowed);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate * getalgbyname - read crypt.conf(4) looking for algname
4767c478bd9Sstevel@tonic-gate *
4777c478bd9Sstevel@tonic-gate * RETURN VALUES
4787c478bd9Sstevel@tonic-gate * On error NULL and errno is set
4797c478bd9Sstevel@tonic-gate * On success the alg details including an open handle to the lib
4807c478bd9Sstevel@tonic-gate * If crypt.conf(4) is okay but algname doesn't exist in it then
4817c478bd9Sstevel@tonic-gate * return NULL the caller should then use the default algorithm
4827c478bd9Sstevel@tonic-gate * as per the policy.
4837c478bd9Sstevel@tonic-gate */
4847c478bd9Sstevel@tonic-gate static struct crypt_alg_s *
getalgbyname(const char * algname,boolean_t * found)4857c478bd9Sstevel@tonic-gate getalgbyname(const char *algname, boolean_t *found)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate struct stat stb;
4887c478bd9Sstevel@tonic-gate int configfd;
4897c478bd9Sstevel@tonic-gate FILE *fconf = NULL;
4907c478bd9Sstevel@tonic-gate struct crypt_alg_s *alg = NULL;
4917c478bd9Sstevel@tonic-gate char line[CRYPT_CONFLINELENGTH];
4927c478bd9Sstevel@tonic-gate int linelen = 0;
4937c478bd9Sstevel@tonic-gate int lineno = 0;
4947c478bd9Sstevel@tonic-gate char *pathname = NULL;
4957c478bd9Sstevel@tonic-gate char *lasts = NULL;
4967c478bd9Sstevel@tonic-gate char *token = NULL;
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate *found = B_FALSE;
4997c478bd9Sstevel@tonic-gate if ((algname == NULL) || (strcmp(algname, CRYPT_UNIX) == 0)) {
5007c478bd9Sstevel@tonic-gate return (NULL);
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate if ((configfd = open(CRYPT_CONFFILE, O_RDONLY)) == -1) {
5047c478bd9Sstevel@tonic-gate syslog(LOG_ALERT, "crypt: open(%s) failed: %s",
5057c478bd9Sstevel@tonic-gate CRYPT_CONFFILE, strerror(errno));
5067c478bd9Sstevel@tonic-gate return (NULL);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate /*
5107c478bd9Sstevel@tonic-gate * Stat the file so we can check modes and ownerships
5117c478bd9Sstevel@tonic-gate */
5127c478bd9Sstevel@tonic-gate if (fstat(configfd, &stb) < 0) {
5137c478bd9Sstevel@tonic-gate syslog(LOG_ALERT, "crypt: stat(%s) failed: %s",
5147c478bd9Sstevel@tonic-gate CRYPT_CONFFILE, strerror(errno));
5157c478bd9Sstevel@tonic-gate goto cleanup;
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate /*
5197c478bd9Sstevel@tonic-gate * Check the ownership of the file
5207c478bd9Sstevel@tonic-gate */
5217c478bd9Sstevel@tonic-gate if (stb.st_uid != (uid_t)0) {
5227c478bd9Sstevel@tonic-gate syslog(LOG_ALERT,
5237c478bd9Sstevel@tonic-gate "crypt: Owner of %s is not root", CRYPT_CONFFILE);
5247c478bd9Sstevel@tonic-gate goto cleanup;
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate * Check the modes on the file
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate if (stb.st_mode & S_IWGRP) {
5317c478bd9Sstevel@tonic-gate syslog(LOG_ALERT,
5327c478bd9Sstevel@tonic-gate "crypt: %s writable by group", CRYPT_CONFFILE);
5337c478bd9Sstevel@tonic-gate goto cleanup;
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate if (stb.st_mode & S_IWOTH) {
5367c478bd9Sstevel@tonic-gate syslog(LOG_ALERT,
5377c478bd9Sstevel@tonic-gate "crypt: %s writable by world", CRYPT_CONFFILE);
5387c478bd9Sstevel@tonic-gate goto cleanup;
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate
541004388ebScasper if ((fconf = fdopen(configfd, "rF")) == NULL) {
5427c478bd9Sstevel@tonic-gate syslog(LOG_ALERT, "crypt: fdopen(%d) failed: %s",
5437c478bd9Sstevel@tonic-gate configfd, strerror(errno));
5447c478bd9Sstevel@tonic-gate goto cleanup;
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate /*
5487c478bd9Sstevel@tonic-gate * /etc/security/crypt.conf has 3 fields:
5497c478bd9Sstevel@tonic-gate * <algname> <pathname> [<name[=val]>[<name[=val]>]]
5507c478bd9Sstevel@tonic-gate */
5517c478bd9Sstevel@tonic-gate errno = 0;
5527c478bd9Sstevel@tonic-gate while (!(*found) &&
5537c478bd9Sstevel@tonic-gate ((fgets(line, sizeof (line), fconf) != NULL) && !feof(fconf))) {
5547c478bd9Sstevel@tonic-gate lineno++;
5557c478bd9Sstevel@tonic-gate /*
5567c478bd9Sstevel@tonic-gate * Skip over comments
5577c478bd9Sstevel@tonic-gate */
5587c478bd9Sstevel@tonic-gate if ((line[0] == '#') || (line[0] == '\n')) {
5597c478bd9Sstevel@tonic-gate continue;
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate linelen = strlen(line);
5637c478bd9Sstevel@tonic-gate line[--linelen] = '\0'; /* chop the trailing \n */
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate token = strtok_r(line, " \t", &lasts);
5667c478bd9Sstevel@tonic-gate if (token == NULL) {
5677c478bd9Sstevel@tonic-gate continue;
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate if (strcmp(token, algname) == 0) {
5707c478bd9Sstevel@tonic-gate *found = B_TRUE;
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate if (!found) {
5747c478bd9Sstevel@tonic-gate errno = EINVAL;
5757c478bd9Sstevel@tonic-gate goto cleanup;
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate token = strtok_r(NULL, " \t", &lasts);
5797c478bd9Sstevel@tonic-gate if (token == NULL) {
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate * Broken config file
5827c478bd9Sstevel@tonic-gate */
5837c478bd9Sstevel@tonic-gate syslog(LOG_ALERT, "crypt(3c): %s may be corrupt at line %d",
5847c478bd9Sstevel@tonic-gate CRYPT_CONFFILE, lineno);
5857c478bd9Sstevel@tonic-gate *found = B_FALSE;
5867c478bd9Sstevel@tonic-gate errno = EINVAL;
5877c478bd9Sstevel@tonic-gate goto cleanup;
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate if ((pathname = isa_path(token)) == NULL) {
5917c478bd9Sstevel@tonic-gate if (errno != ENOMEM)
5927c478bd9Sstevel@tonic-gate errno = EINVAL;
5937c478bd9Sstevel@tonic-gate *found = B_FALSE;
5947c478bd9Sstevel@tonic-gate goto cleanup;
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate if ((alg = malloc(sizeof (struct crypt_alg_s))) == NULL) {
5987c478bd9Sstevel@tonic-gate *found = B_FALSE;
5997c478bd9Sstevel@tonic-gate goto cleanup;
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate alg->a_libhandle = NULL;
6027c478bd9Sstevel@tonic-gate alg->a_genhash = NULL;
6037c478bd9Sstevel@tonic-gate alg->a_gensalt = NULL;
6047c478bd9Sstevel@tonic-gate alg->a_params = NULL;
6057c478bd9Sstevel@tonic-gate alg->a_nparams = 0;
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate /*
6087c478bd9Sstevel@tonic-gate * The rest of the line is module specific params, space
6097c478bd9Sstevel@tonic-gate * seprated. We wait until after we have checked the module is
6107c478bd9Sstevel@tonic-gate * valid before parsing them into a_params, this saves us
6117c478bd9Sstevel@tonic-gate * having to free them later if there is a problem.
6127c478bd9Sstevel@tonic-gate */
6137c478bd9Sstevel@tonic-gate if ((alg->a_libhandle = dlopen(pathname, RTLD_NOW)) == NULL) {
6147c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "crypt(3c) unable to dlopen %s: %s",
6157c478bd9Sstevel@tonic-gate pathname, dlerror());
6167c478bd9Sstevel@tonic-gate errno = ELIBACC;
6177c478bd9Sstevel@tonic-gate *found = B_FALSE;
6187c478bd9Sstevel@tonic-gate goto cleanup;
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate alg->a_genhash =
6227c478bd9Sstevel@tonic-gate (char *(*)())dlsym(alg->a_libhandle, "crypt_genhash_impl");
6237c478bd9Sstevel@tonic-gate if (alg->a_genhash == NULL) {
6247c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "crypt(3c) unable to find cryp_genhash_impl"
6257c478bd9Sstevel@tonic-gate "symbol in %s: %s", pathname, dlerror());
6267c478bd9Sstevel@tonic-gate errno = ELIBACC;
6277c478bd9Sstevel@tonic-gate *found = B_FALSE;
6287c478bd9Sstevel@tonic-gate goto cleanup;
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate alg->a_gensalt =
6317c478bd9Sstevel@tonic-gate (char *(*)())dlsym(alg->a_libhandle, "crypt_gensalt_impl");
6327c478bd9Sstevel@tonic-gate if (alg->a_gensalt == NULL) {
6337c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "crypt(3c) unable to find crypt_gensalt_impl"
6347c478bd9Sstevel@tonic-gate "symbol in %s: %s", pathname, dlerror());
6357c478bd9Sstevel@tonic-gate errno = ELIBACC;
6367c478bd9Sstevel@tonic-gate *found = B_FALSE;
6377c478bd9Sstevel@tonic-gate goto cleanup;
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate * We have a good module so build the a_params if we have any.
6427c478bd9Sstevel@tonic-gate * Count how much space we need first and then allocate an array
6437c478bd9Sstevel@tonic-gate * to hold that many module params.
6447c478bd9Sstevel@tonic-gate */
6457c478bd9Sstevel@tonic-gate if (lasts != NULL) {
6467c478bd9Sstevel@tonic-gate int nparams = 0;
6477c478bd9Sstevel@tonic-gate char *tparams;
6487c478bd9Sstevel@tonic-gate char *tplasts;
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate if ((tparams = strdup(lasts)) == NULL) {
6517c478bd9Sstevel@tonic-gate *found = B_FALSE;
6527c478bd9Sstevel@tonic-gate goto cleanup;
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate (void) strtok_r(tparams, " \t", &tplasts);
6567c478bd9Sstevel@tonic-gate do {
6577c478bd9Sstevel@tonic-gate nparams++;
6587c478bd9Sstevel@tonic-gate } while (strtok_r(NULL, " \t", &tplasts) != NULL);
6597c478bd9Sstevel@tonic-gate free(tparams);
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate alg->a_params = calloc(nparams + 1, sizeof (char *));
6627c478bd9Sstevel@tonic-gate if (alg->a_params == NULL) {
6637c478bd9Sstevel@tonic-gate *found = B_FALSE;
6647c478bd9Sstevel@tonic-gate goto cleanup;
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate while ((token = strtok_r(NULL, " \t", &lasts)) != NULL) {
6687c478bd9Sstevel@tonic-gate alg->a_params[alg->a_nparams++] = token;
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate cleanup:
6737c478bd9Sstevel@tonic-gate if (*found == B_FALSE) {
6747c478bd9Sstevel@tonic-gate free_crypt_alg(alg);
6757c478bd9Sstevel@tonic-gate alg = NULL;
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate if (pathname != NULL) {
6797c478bd9Sstevel@tonic-gate free(pathname);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate if (fconf != NULL) {
6837c478bd9Sstevel@tonic-gate (void) fclose(fconf);
6847c478bd9Sstevel@tonic-gate } else {
6857c478bd9Sstevel@tonic-gate (void) close(configfd);
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate return (alg);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate static void
free_crypt_alg(struct crypt_alg_s * alg)6927c478bd9Sstevel@tonic-gate free_crypt_alg(struct crypt_alg_s *alg)
6937c478bd9Sstevel@tonic-gate {
6947c478bd9Sstevel@tonic-gate if (alg == NULL)
6957c478bd9Sstevel@tonic-gate return;
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate if (alg->a_libhandle != NULL) {
6987c478bd9Sstevel@tonic-gate (void) dlclose(alg->a_libhandle);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate if (alg->a_nparams != NULL) {
7017c478bd9Sstevel@tonic-gate free(alg->a_params);
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate free(alg);
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate static void
free_crypt_policy(struct crypt_policy_s * policy)7077c478bd9Sstevel@tonic-gate free_crypt_policy(struct crypt_policy_s *policy)
7087c478bd9Sstevel@tonic-gate {
7097c478bd9Sstevel@tonic-gate if (policy == NULL)
7107c478bd9Sstevel@tonic-gate return;
7117c478bd9Sstevel@tonic-gate
7127c478bd9Sstevel@tonic-gate if (policy->cp_default != NULL) {
7137c478bd9Sstevel@tonic-gate bzero(policy->cp_default, strlen(policy->cp_default));
7147c478bd9Sstevel@tonic-gate free(policy->cp_default);
7157c478bd9Sstevel@tonic-gate policy->cp_default = NULL;
7167c478bd9Sstevel@tonic-gate }
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate if (policy->cp_allow != NULL) {
7197c478bd9Sstevel@tonic-gate bzero(policy->cp_allow, strlen(policy->cp_allow));
7207c478bd9Sstevel@tonic-gate free(policy->cp_allow);
7217c478bd9Sstevel@tonic-gate policy->cp_allow = NULL;
7227c478bd9Sstevel@tonic-gate }
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate if (policy->cp_deny != NULL) {
7257c478bd9Sstevel@tonic-gate bzero(policy->cp_deny, strlen(policy->cp_deny));
7267c478bd9Sstevel@tonic-gate free(policy->cp_deny);
7277c478bd9Sstevel@tonic-gate policy->cp_deny = NULL;
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate free(policy);
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate
7347c478bd9Sstevel@tonic-gate /*
7357c478bd9Sstevel@tonic-gate * isa_path - prepend the default dir or patch up the $ISA in path
7367c478bd9Sstevel@tonic-gate * Caller is responsible for calling free(3c) on the result.
7377c478bd9Sstevel@tonic-gate */
7387c478bd9Sstevel@tonic-gate static char *
isa_path(const char * path)7397c478bd9Sstevel@tonic-gate isa_path(const char *path)
7407c478bd9Sstevel@tonic-gate {
7417c478bd9Sstevel@tonic-gate char *ret = NULL;
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate if ((path == NULL) || (strlen(path) > PATH_MAX)) {
7447c478bd9Sstevel@tonic-gate return (NULL);
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate ret = calloc(PATH_MAX, sizeof (char));
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate /*
7507c478bd9Sstevel@tonic-gate * Module path doesn't start with "/" then prepend
7517c478bd9Sstevel@tonic-gate * the default search path CRYPT_MODULE_DIR (/usr/lib/security/$ISA)
7527c478bd9Sstevel@tonic-gate */
7537c478bd9Sstevel@tonic-gate if (path[0] != '/') {
7547c478bd9Sstevel@tonic-gate if (snprintf(ret, PATH_MAX, "%s%s", CRYPT_MODULE_DIR,
7557c478bd9Sstevel@tonic-gate path) > PATH_MAX) {
7567c478bd9Sstevel@tonic-gate free(ret);
7577c478bd9Sstevel@tonic-gate return (NULL);
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate } else { /* patch up $ISA */
7607c478bd9Sstevel@tonic-gate char *isa;
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate if ((isa = strstr(path, CRYPT_MODULE_ISA)) != NULL) {
7637c478bd9Sstevel@tonic-gate *isa = '\0';
7647c478bd9Sstevel@tonic-gate isa += strlen(CRYPT_MODULE_ISA);
7657c478bd9Sstevel@tonic-gate if (snprintf(ret, PATH_MAX, "%s%s%s", path,
7667c478bd9Sstevel@tonic-gate CRYPT_ISA_DIR, isa) > PATH_MAX) {
7677c478bd9Sstevel@tonic-gate free(ret);
7687c478bd9Sstevel@tonic-gate return (NULL);
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate } else {
7717c478bd9Sstevel@tonic-gate free(ret);
7727c478bd9Sstevel@tonic-gate ret = strdup(path);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate
7767c478bd9Sstevel@tonic-gate return (ret);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7817c478bd9Sstevel@tonic-gate static char *
_unix_crypt_gensalt(char * gsbuffer,size_t gsbufflen,const char * oldpuresalt,const struct passwd * userinfo,const char * argv[])7827c478bd9Sstevel@tonic-gate _unix_crypt_gensalt(char *gsbuffer,
7837c478bd9Sstevel@tonic-gate size_t gsbufflen,
7847c478bd9Sstevel@tonic-gate const char *oldpuresalt,
7857c478bd9Sstevel@tonic-gate const struct passwd *userinfo,
7867c478bd9Sstevel@tonic-gate const char *argv[])
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate static const char saltchars[] =
7897c478bd9Sstevel@tonic-gate "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
7907c478bd9Sstevel@tonic-gate struct timeval tv;
7917c478bd9Sstevel@tonic-gate
792*5ad42b1bSSurya Prakki (void) gettimeofday(&tv, (void *) 0);
7937c478bd9Sstevel@tonic-gate srand48(tv.tv_sec ^ tv.tv_usec);
7947c478bd9Sstevel@tonic-gate gsbuffer[0] = saltchars[lrand48() % 64]; /* lrand48() is MT-SAFE */
7957c478bd9Sstevel@tonic-gate gsbuffer[1] = saltchars[lrand48() % 64]; /* lrand48() is MT-SAFE */
7967c478bd9Sstevel@tonic-gate gsbuffer[2] = '\0';
7977c478bd9Sstevel@tonic-gate
7987c478bd9Sstevel@tonic-gate return (gsbuffer);
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate /*
8027c478bd9Sstevel@tonic-gate * The rest of the code below comes from the old crypt.c and is the
8037c478bd9Sstevel@tonic-gate * implementation of the hardwired/fallback traditional algorithm
8047c478bd9Sstevel@tonic-gate * It has been otimized to take better advantage of MT features.
8057c478bd9Sstevel@tonic-gate *
8067c478bd9Sstevel@tonic-gate * It is included here to reduce the overhead of dlopen()
8077c478bd9Sstevel@tonic-gate * for the common case.
8087c478bd9Sstevel@tonic-gate */
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate
8117c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */
8127c478bd9Sstevel@tonic-gate /* All Rights Reserved */
8137c478bd9Sstevel@tonic-gate
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate /*
8177c478bd9Sstevel@tonic-gate * This program implements a data encryption algorithm to encrypt passwords.
8187c478bd9Sstevel@tonic-gate */
8197c478bd9Sstevel@tonic-gate
8207c478bd9Sstevel@tonic-gate static mutex_t crypt_lock = DEFAULTMUTEX;
8217c478bd9Sstevel@tonic-gate #define TSDBUFSZ (66 + 16)
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate static const char IP[] = {
8247c478bd9Sstevel@tonic-gate 58, 50, 42, 34, 26, 18, 10, 2,
8257c478bd9Sstevel@tonic-gate 60, 52, 44, 36, 28, 20, 12, 4,
8267c478bd9Sstevel@tonic-gate 62, 54, 46, 38, 30, 22, 14, 6,
8277c478bd9Sstevel@tonic-gate 64, 56, 48, 40, 32, 24, 16, 8,
8287c478bd9Sstevel@tonic-gate 57, 49, 41, 33, 25, 17, 9, 1,
8297c478bd9Sstevel@tonic-gate 59, 51, 43, 35, 27, 19, 11, 3,
8307c478bd9Sstevel@tonic-gate 61, 53, 45, 37, 29, 21, 13, 5,
8317c478bd9Sstevel@tonic-gate 63, 55, 47, 39, 31, 23, 15, 7,
8327c478bd9Sstevel@tonic-gate };
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate static const char FP[] = {
8357c478bd9Sstevel@tonic-gate 40, 8, 48, 16, 56, 24, 64, 32,
8367c478bd9Sstevel@tonic-gate 39, 7, 47, 15, 55, 23, 63, 31,
8377c478bd9Sstevel@tonic-gate 38, 6, 46, 14, 54, 22, 62, 30,
8387c478bd9Sstevel@tonic-gate 37, 5, 45, 13, 53, 21, 61, 29,
8397c478bd9Sstevel@tonic-gate 36, 4, 44, 12, 52, 20, 60, 28,
8407c478bd9Sstevel@tonic-gate 35, 3, 43, 11, 51, 19, 59, 27,
8417c478bd9Sstevel@tonic-gate 34, 2, 42, 10, 50, 18, 58, 26,
8427c478bd9Sstevel@tonic-gate 33, 1, 41, 9, 49, 17, 57, 25,
8437c478bd9Sstevel@tonic-gate };
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate static const char PC1_C[] = {
8467c478bd9Sstevel@tonic-gate 57, 49, 41, 33, 25, 17, 9,
8477c478bd9Sstevel@tonic-gate 1, 58, 50, 42, 34, 26, 18,
8487c478bd9Sstevel@tonic-gate 10, 2, 59, 51, 43, 35, 27,
8497c478bd9Sstevel@tonic-gate 19, 11, 3, 60, 52, 44, 36,
8507c478bd9Sstevel@tonic-gate };
8517c478bd9Sstevel@tonic-gate
8527c478bd9Sstevel@tonic-gate static const char PC1_D[] = {
8537c478bd9Sstevel@tonic-gate 63, 55, 47, 39, 31, 23, 15,
8547c478bd9Sstevel@tonic-gate 7, 62, 54, 46, 38, 30, 22,
8557c478bd9Sstevel@tonic-gate 14, 6, 61, 53, 45, 37, 29,
8567c478bd9Sstevel@tonic-gate 21, 13, 5, 28, 20, 12, 4,
8577c478bd9Sstevel@tonic-gate };
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate static const char shifts[] = {
8607c478bd9Sstevel@tonic-gate 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
8617c478bd9Sstevel@tonic-gate };
8627c478bd9Sstevel@tonic-gate
8637c478bd9Sstevel@tonic-gate static const char PC2_C[] = {
8647c478bd9Sstevel@tonic-gate 14, 17, 11, 24, 1, 5,
8657c478bd9Sstevel@tonic-gate 3, 28, 15, 6, 21, 10,
8667c478bd9Sstevel@tonic-gate 23, 19, 12, 4, 26, 8,
8677c478bd9Sstevel@tonic-gate 16, 7, 27, 20, 13, 2,
8687c478bd9Sstevel@tonic-gate };
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate static const char PC2_D[] = {
8717c478bd9Sstevel@tonic-gate 41, 52, 31, 37, 47, 55,
8727c478bd9Sstevel@tonic-gate 30, 40, 51, 45, 33, 48,
8737c478bd9Sstevel@tonic-gate 44, 49, 39, 56, 34, 53,
8747c478bd9Sstevel@tonic-gate 46, 42, 50, 36, 29, 32,
8757c478bd9Sstevel@tonic-gate };
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate static char C[28];
8787c478bd9Sstevel@tonic-gate static char D[28];
8797c478bd9Sstevel@tonic-gate static char *KS;
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate static char E[48];
8827c478bd9Sstevel@tonic-gate static const char e2[] = {
8837c478bd9Sstevel@tonic-gate 32, 1, 2, 3, 4, 5,
8847c478bd9Sstevel@tonic-gate 4, 5, 6, 7, 8, 9,
8857c478bd9Sstevel@tonic-gate 8, 9, 10, 11, 12, 13,
8867c478bd9Sstevel@tonic-gate 12, 13, 14, 15, 16, 17,
8877c478bd9Sstevel@tonic-gate 16, 17, 18, 19, 20, 21,
8887c478bd9Sstevel@tonic-gate 20, 21, 22, 23, 24, 25,
8897c478bd9Sstevel@tonic-gate 24, 25, 26, 27, 28, 29,
8907c478bd9Sstevel@tonic-gate 28, 29, 30, 31, 32, 1,
8917c478bd9Sstevel@tonic-gate };
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate /*
8947c478bd9Sstevel@tonic-gate * The KS array (768 bytes) is allocated once, and only if
8957c478bd9Sstevel@tonic-gate * one of _unix_crypt(), encrypt() or setkey() is called.
8967c478bd9Sstevel@tonic-gate * The complexity below is due to the fact that calloc()
8977c478bd9Sstevel@tonic-gate * must not be called while holding any locks.
8987c478bd9Sstevel@tonic-gate */
8997c478bd9Sstevel@tonic-gate static int
allocate_KS(void)9007c478bd9Sstevel@tonic-gate allocate_KS(void)
9017c478bd9Sstevel@tonic-gate {
9027c478bd9Sstevel@tonic-gate char *ks;
9037c478bd9Sstevel@tonic-gate int failed;
9047c478bd9Sstevel@tonic-gate int assigned;
9057c478bd9Sstevel@tonic-gate
906cb620785Sraf if (KS != NULL) { /* already allocated */
907cb620785Sraf membar_consumer();
9087c478bd9Sstevel@tonic-gate return (0);
909cb620785Sraf }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate ks = calloc(16, 48 * sizeof (char));
9127c478bd9Sstevel@tonic-gate failed = 0;
9137c478bd9Sstevel@tonic-gate lmutex_lock(&crypt_lock);
9147c478bd9Sstevel@tonic-gate if (KS != NULL) { /* someone else got here first */
9157c478bd9Sstevel@tonic-gate assigned = 0;
9167c478bd9Sstevel@tonic-gate } else {
9177c478bd9Sstevel@tonic-gate assigned = 1;
918cb620785Sraf membar_producer();
9197c478bd9Sstevel@tonic-gate if ((KS = ks) == NULL) /* calloc() failed */
9207c478bd9Sstevel@tonic-gate failed = 1;
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate lmutex_unlock(&crypt_lock);
9237c478bd9Sstevel@tonic-gate if (!assigned)
9247c478bd9Sstevel@tonic-gate free(ks);
9257c478bd9Sstevel@tonic-gate return (failed);
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate static void
unlocked_setkey(const char * key)9297c478bd9Sstevel@tonic-gate unlocked_setkey(const char *key)
9307c478bd9Sstevel@tonic-gate {
9317c478bd9Sstevel@tonic-gate int i, j, k;
9327c478bd9Sstevel@tonic-gate char t;
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate for (i = 0; i < 28; i++) {
9357c478bd9Sstevel@tonic-gate C[i] = key[PC1_C[i]-1];
9367c478bd9Sstevel@tonic-gate D[i] = key[PC1_D[i]-1];
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) {
9397c478bd9Sstevel@tonic-gate for (k = 0; k < shifts[i]; k++) {
9407c478bd9Sstevel@tonic-gate t = C[0];
9417c478bd9Sstevel@tonic-gate for (j = 0; j < 28-1; j++)
9427c478bd9Sstevel@tonic-gate C[j] = C[j+1];
9437c478bd9Sstevel@tonic-gate C[27] = t;
9447c478bd9Sstevel@tonic-gate t = D[0];
9457c478bd9Sstevel@tonic-gate for (j = 0; j < 28-1; j++)
9467c478bd9Sstevel@tonic-gate D[j] = D[j+1];
9477c478bd9Sstevel@tonic-gate D[27] = t;
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate for (j = 0; j < 24; j++) {
9507c478bd9Sstevel@tonic-gate int index = i * 48;
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate *(KS+index+j) = C[PC2_C[j]-1];
9537c478bd9Sstevel@tonic-gate *(KS+index+j+24) = D[PC2_D[j]-28-1];
9547c478bd9Sstevel@tonic-gate }
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate for (i = 0; i < 48; i++)
9577c478bd9Sstevel@tonic-gate E[i] = e2[i];
9587c478bd9Sstevel@tonic-gate }
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate static const char S[8][64] = {
9617c478bd9Sstevel@tonic-gate 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
9627c478bd9Sstevel@tonic-gate 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
9637c478bd9Sstevel@tonic-gate 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
9647c478bd9Sstevel@tonic-gate 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
9677c478bd9Sstevel@tonic-gate 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
9687c478bd9Sstevel@tonic-gate 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
9697c478bd9Sstevel@tonic-gate 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
9707c478bd9Sstevel@tonic-gate
9717c478bd9Sstevel@tonic-gate 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
9727c478bd9Sstevel@tonic-gate 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
9737c478bd9Sstevel@tonic-gate 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
9747c478bd9Sstevel@tonic-gate 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
9757c478bd9Sstevel@tonic-gate
9767c478bd9Sstevel@tonic-gate 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
9777c478bd9Sstevel@tonic-gate 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
9787c478bd9Sstevel@tonic-gate 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
9797c478bd9Sstevel@tonic-gate 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
9827c478bd9Sstevel@tonic-gate 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
9837c478bd9Sstevel@tonic-gate 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
9847c478bd9Sstevel@tonic-gate 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
9857c478bd9Sstevel@tonic-gate
9867c478bd9Sstevel@tonic-gate 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
9877c478bd9Sstevel@tonic-gate 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9887c478bd9Sstevel@tonic-gate 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
9897c478bd9Sstevel@tonic-gate 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
9907c478bd9Sstevel@tonic-gate
9917c478bd9Sstevel@tonic-gate 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
9927c478bd9Sstevel@tonic-gate 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
9937c478bd9Sstevel@tonic-gate 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
9947c478bd9Sstevel@tonic-gate 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
9957c478bd9Sstevel@tonic-gate
9967c478bd9Sstevel@tonic-gate 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
9977c478bd9Sstevel@tonic-gate 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
9987c478bd9Sstevel@tonic-gate 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
9997c478bd9Sstevel@tonic-gate 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11,
10007c478bd9Sstevel@tonic-gate };
10017c478bd9Sstevel@tonic-gate
10027c478bd9Sstevel@tonic-gate static const char P[] = {
10037c478bd9Sstevel@tonic-gate 16, 7, 20, 21,
10047c478bd9Sstevel@tonic-gate 29, 12, 28, 17,
10057c478bd9Sstevel@tonic-gate 1, 15, 23, 26,
10067c478bd9Sstevel@tonic-gate 5, 18, 31, 10,
10077c478bd9Sstevel@tonic-gate 2, 8, 24, 14,
10087c478bd9Sstevel@tonic-gate 32, 27, 3, 9,
10097c478bd9Sstevel@tonic-gate 19, 13, 30, 6,
10107c478bd9Sstevel@tonic-gate 22, 11, 4, 25,
10117c478bd9Sstevel@tonic-gate };
10127c478bd9Sstevel@tonic-gate
10137c478bd9Sstevel@tonic-gate static char L[64];
10147c478bd9Sstevel@tonic-gate static char tempL[32];
10157c478bd9Sstevel@tonic-gate static char f[32];
10167c478bd9Sstevel@tonic-gate
10177c478bd9Sstevel@tonic-gate static char preS[48];
10187c478bd9Sstevel@tonic-gate
10197c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10207c478bd9Sstevel@tonic-gate static void
unlocked_encrypt(char * block,int fake)10217c478bd9Sstevel@tonic-gate unlocked_encrypt(char *block, int fake)
10227c478bd9Sstevel@tonic-gate {
10237c478bd9Sstevel@tonic-gate int i;
10247c478bd9Sstevel@tonic-gate int t, j, k;
10257c478bd9Sstevel@tonic-gate char *R = &L[32];
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate for (j = 0; j < 64; j++)
10287c478bd9Sstevel@tonic-gate L[j] = block[IP[j]-1];
10297c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) {
10307c478bd9Sstevel@tonic-gate int index = i * 48;
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate for (j = 0; j < 32; j++)
10337c478bd9Sstevel@tonic-gate tempL[j] = R[j];
10347c478bd9Sstevel@tonic-gate for (j = 0; j < 48; j++)
10357c478bd9Sstevel@tonic-gate preS[j] = R[E[j]-1] ^ *(KS+index+j);
10367c478bd9Sstevel@tonic-gate for (j = 0; j < 8; j++) {
10377c478bd9Sstevel@tonic-gate t = 6 * j;
10387c478bd9Sstevel@tonic-gate k = S[j][(preS[t+0]<<5) +
10397c478bd9Sstevel@tonic-gate (preS[t+1]<<3) +
10407c478bd9Sstevel@tonic-gate (preS[t+2]<<2) +
10417c478bd9Sstevel@tonic-gate (preS[t+3]<<1) +
10427c478bd9Sstevel@tonic-gate (preS[t+4]<<0) +
10437c478bd9Sstevel@tonic-gate (preS[t+5]<<4)];
10447c478bd9Sstevel@tonic-gate t = 4*j;
10457c478bd9Sstevel@tonic-gate f[t+0] = (k>>3)&01;
10467c478bd9Sstevel@tonic-gate f[t+1] = (k>>2)&01;
10477c478bd9Sstevel@tonic-gate f[t+2] = (k>>1)&01;
10487c478bd9Sstevel@tonic-gate f[t+3] = (k>>0)&01;
10497c478bd9Sstevel@tonic-gate }
10507c478bd9Sstevel@tonic-gate for (j = 0; j < 32; j++)
10517c478bd9Sstevel@tonic-gate R[j] = L[j] ^ f[P[j]-1];
10527c478bd9Sstevel@tonic-gate for (j = 0; j < 32; j++)
10537c478bd9Sstevel@tonic-gate L[j] = tempL[j];
10547c478bd9Sstevel@tonic-gate }
10557c478bd9Sstevel@tonic-gate for (j = 0; j < 32; j++) {
10567c478bd9Sstevel@tonic-gate t = L[j];
10577c478bd9Sstevel@tonic-gate L[j] = R[j];
10587c478bd9Sstevel@tonic-gate R[j] = (char)t;
10597c478bd9Sstevel@tonic-gate }
10607c478bd9Sstevel@tonic-gate for (j = 0; j < 64; j++)
10617c478bd9Sstevel@tonic-gate block[j] = L[FP[j]-1];
10627c478bd9Sstevel@tonic-gate }
10637c478bd9Sstevel@tonic-gate
10647c478bd9Sstevel@tonic-gate char *
_unix_crypt(const char * pw,const char * salt,char * iobuf)10657c478bd9Sstevel@tonic-gate _unix_crypt(const char *pw, const char *salt, char *iobuf)
10667c478bd9Sstevel@tonic-gate {
10677c478bd9Sstevel@tonic-gate int c, i, j;
10687c478bd9Sstevel@tonic-gate char temp;
10697c478bd9Sstevel@tonic-gate char *block;
10707c478bd9Sstevel@tonic-gate
10717c478bd9Sstevel@tonic-gate block = iobuf + 16;
10727c478bd9Sstevel@tonic-gate
10737c478bd9Sstevel@tonic-gate if (iobuf == 0) {
10747c478bd9Sstevel@tonic-gate errno = ENOMEM;
10757c478bd9Sstevel@tonic-gate return (NULL);
10767c478bd9Sstevel@tonic-gate }
10777c478bd9Sstevel@tonic-gate if (allocate_KS() != 0)
10787c478bd9Sstevel@tonic-gate return (NULL);
10797c478bd9Sstevel@tonic-gate lmutex_lock(&crypt_lock);
10807c478bd9Sstevel@tonic-gate for (i = 0; i < 66; i++)
10817c478bd9Sstevel@tonic-gate block[i] = 0;
10827c478bd9Sstevel@tonic-gate for (i = 0; (c = *pw) != '\0' && i < 64; pw++) {
10837c478bd9Sstevel@tonic-gate for (j = 0; j < 7; j++, i++)
10847c478bd9Sstevel@tonic-gate block[i] = (c>>(6-j)) & 01;
10857c478bd9Sstevel@tonic-gate i++;
10867c478bd9Sstevel@tonic-gate }
10877c478bd9Sstevel@tonic-gate
10887c478bd9Sstevel@tonic-gate unlocked_setkey(block);
10897c478bd9Sstevel@tonic-gate
10907c478bd9Sstevel@tonic-gate for (i = 0; i < 66; i++)
10917c478bd9Sstevel@tonic-gate block[i] = 0;
10927c478bd9Sstevel@tonic-gate
10937c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) {
10947c478bd9Sstevel@tonic-gate c = *salt++;
10957c478bd9Sstevel@tonic-gate iobuf[i] = (char)c;
10967c478bd9Sstevel@tonic-gate if (c > 'Z')
10977c478bd9Sstevel@tonic-gate c -= 6;
10987c478bd9Sstevel@tonic-gate if (c > '9')
10997c478bd9Sstevel@tonic-gate c -= 7;
11007c478bd9Sstevel@tonic-gate c -= '.';
11017c478bd9Sstevel@tonic-gate for (j = 0; j < 6; j++) {
11027c478bd9Sstevel@tonic-gate if ((c>>j) & 01) {
11037c478bd9Sstevel@tonic-gate temp = E[6*i+j];
11047c478bd9Sstevel@tonic-gate E[6*i+j] = E[6*i+j+24];
11057c478bd9Sstevel@tonic-gate E[6*i+j+24] = temp;
11067c478bd9Sstevel@tonic-gate }
11077c478bd9Sstevel@tonic-gate }
11087c478bd9Sstevel@tonic-gate }
11097c478bd9Sstevel@tonic-gate
11107c478bd9Sstevel@tonic-gate for (i = 0; i < 25; i++)
11117c478bd9Sstevel@tonic-gate unlocked_encrypt(block, 0);
11127c478bd9Sstevel@tonic-gate
11137c478bd9Sstevel@tonic-gate lmutex_unlock(&crypt_lock);
11147c478bd9Sstevel@tonic-gate for (i = 0; i < 11; i++) {
11157c478bd9Sstevel@tonic-gate c = 0;
11167c478bd9Sstevel@tonic-gate for (j = 0; j < 6; j++) {
11177c478bd9Sstevel@tonic-gate c <<= 1;
11187c478bd9Sstevel@tonic-gate c |= block[6*i+j];
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate c += '.';
11217c478bd9Sstevel@tonic-gate if (c > '9')
11227c478bd9Sstevel@tonic-gate c += 7;
11237c478bd9Sstevel@tonic-gate if (c > 'Z')
11247c478bd9Sstevel@tonic-gate c += 6;
11257c478bd9Sstevel@tonic-gate iobuf[i+2] = (char)c;
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate iobuf[i+2] = 0;
11287c478bd9Sstevel@tonic-gate if (iobuf[1] == 0)
11297c478bd9Sstevel@tonic-gate iobuf[1] = iobuf[0];
11307c478bd9Sstevel@tonic-gate return (iobuf);
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate
11337c478bd9Sstevel@tonic-gate
11347c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11357c478bd9Sstevel@tonic-gate void
encrypt(char * block,int fake)11367c478bd9Sstevel@tonic-gate encrypt(char *block, int fake)
11377c478bd9Sstevel@tonic-gate {
11387c478bd9Sstevel@tonic-gate if (fake != 0) {
11397c478bd9Sstevel@tonic-gate errno = ENOSYS;
11407c478bd9Sstevel@tonic-gate return;
11417c478bd9Sstevel@tonic-gate }
11427c478bd9Sstevel@tonic-gate if (allocate_KS() != 0)
11437c478bd9Sstevel@tonic-gate return;
11447c478bd9Sstevel@tonic-gate lmutex_lock(&crypt_lock);
11457c478bd9Sstevel@tonic-gate unlocked_encrypt(block, fake);
11467c478bd9Sstevel@tonic-gate lmutex_unlock(&crypt_lock);
11477c478bd9Sstevel@tonic-gate }
11487c478bd9Sstevel@tonic-gate
11497c478bd9Sstevel@tonic-gate
11507c478bd9Sstevel@tonic-gate void
setkey(const char * key)11517c478bd9Sstevel@tonic-gate setkey(const char *key)
11527c478bd9Sstevel@tonic-gate {
11537c478bd9Sstevel@tonic-gate if (allocate_KS() != 0)
11547c478bd9Sstevel@tonic-gate return;
11557c478bd9Sstevel@tonic-gate lmutex_lock(&crypt_lock);
11567c478bd9Sstevel@tonic-gate unlocked_setkey(key);
11577c478bd9Sstevel@tonic-gate lmutex_unlock(&crypt_lock);
11587c478bd9Sstevel@tonic-gate }
1159