import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / gen / crypt.c
blobf3bb4ca38e38241f6e97774ccf651b06756b290c
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma weak _crypt = crypt
28 #pragma weak _encrypt = encrypt
29 #pragma weak _setkey = setkey
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>
50 #include <crypt.h>
51 #include <libc.h>
52 #include "tsd.h"
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__"
59 #define CRYPT_CONFFILE "/etc/security/crypt.conf"
60 #define POLICY_CONF_FILE "/etc/security/policy.conf"
62 #define CRYPT_CONFLINELENGTH 1024
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 */
74 * MAX_ALGNAME_LEN:
76 * In practical terms this is probably never any bigger than about 10, but...
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.
84 * CRYPT_MAXCIPHERTEXTLEN is defined in crypt.h and is smaller than
85 * CRYPT_CONFLINELENGTH, and probably always will be.
87 #define MAX_ALGNAME_LEN (CRYPT_MAXCIPHERTEXTLEN - 1)
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;
99 struct crypt_policy_s {
100 char *cp_default;
101 char *cp_allow;
102 char *cp_deny;
105 enum crypt_policy_error_e {
106 CPE_BOTH = 1,
107 CPE_MULTI
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);
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[]);
126 * crypt - string encoding function
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.
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.
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.
143 char *
144 crypt(const char *plaintext, const char *salt)
146 struct crypt_alg_s *alg;
147 char *ctbuffer;
148 char *ciphertext;
149 char *algname;
150 boolean_t found;
152 ctbuffer = tsdalloc(_T_CRYPT, CRYPT_MAXCIPHERTEXTLEN, NULL);
153 if (ctbuffer == NULL)
154 return (NULL);
155 bzero(ctbuffer, CRYPT_MAXCIPHERTEXTLEN);
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.
163 if (salt == NULL || salt[0] != '$' || strlen(salt) == 1) {
164 return (_unix_crypt(plaintext, salt, ctbuffer));
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.
176 if ((algname = getalgfromsalt(salt)) == NULL) {
177 return (NULL);
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);
194 cleanup:
195 free_crypt_alg(alg);
196 free(algname);
198 return (ciphertext);
202 * crypt_gensalt - generate salt string for string encoding
204 * This function generates the salt string pased to crypt(3c).
205 * If oldsalt is NULL, the use the default algorithm.
206 * Other wise check the policy in policy.conf to ensure that it is
207 * either still allowed or not deprecated.
209 * RETURN VALUES
210 * Return a pointer to the new salt, the caller is responsible
211 * for using free(3c) on the return value.
212 * Returns NULL on error and sets errno to one of:
213 * EINVAL, ELIBACC, ENOMEM
215 char *
216 crypt_gensalt(const char *oldsalt, const struct passwd *userinfo)
218 struct crypt_alg_s *alg = NULL;
219 struct crypt_policy_s *policy = NULL;
220 char *newsalt = NULL;
221 char *gsbuffer;
222 char *algname = NULL;
223 boolean_t found;
225 gsbuffer = calloc(CRYPT_MAXCIPHERTEXTLEN, sizeof (char *));
226 if (gsbuffer == NULL) {
227 errno = ENOMEM;
228 goto cleanup;
231 policy = getcryptpolicy();
232 if (policy == NULL) {
233 errno = EINVAL;
234 goto cleanup;
237 algname = getalgfromsalt(oldsalt);
238 if (!alg_valid(algname, policy)) {
239 free(algname);
240 algname = strdup(policy->cp_default);
243 if (strcmp(algname, CRYPT_UNIX) == 0) {
244 newsalt = _unix_crypt_gensalt(gsbuffer, CRYPT_MAXCIPHERTEXTLEN,
245 oldsalt, userinfo, NULL);
246 } else {
247 errno = 0;
248 alg = getalgbyname(algname, &found);
249 if (alg == NULL || !found) {
250 if (errno == 0)
251 errno = EINVAL;
252 goto cleanup;
254 newsalt = alg->a_gensalt(gsbuffer, CRYPT_MAXCIPHERTEXTLEN,
255 oldsalt, userinfo, (const char **)alg->a_params);
258 cleanup:
259 free_crypt_policy(policy);
260 free_crypt_alg(alg);
261 if (newsalt == NULL)
262 free(gsbuffer);
263 free(algname);
265 return (newsalt);
269 * ===========================================================================
270 * The remainder of this file contains internal interfaces for
271 * the implementation of crypt(3c) and crypt_gensalt(3c)
272 * ===========================================================================
277 * getalgfromsalt - extract the algorithm name from the salt string
279 static char *
280 getalgfromsalt(const char *salt)
282 char algname[CRYPT_MAXCIPHERTEXTLEN];
283 int i;
284 int j;
286 if (salt == NULL || strlen(salt) > CRYPT_MAXCIPHERTEXTLEN)
287 return (NULL);
289 * Salts are in this format:
290 * $<algname>[,var=val,[var=val ...][$puresalt]$<ciphertext>
292 * The only bit we need to worry about here is extracting the
293 * name which is the string between the first "$" and the first
294 * of "," or second "$".
296 if (salt[0] != '$') {
297 return (strdup(CRYPT_UNIX));
300 i = 1;
301 j = 0;
302 while (salt[i] != '\0' && salt[i] != '$' && salt[i] != ',') {
303 algname[j] = salt[i];
304 i++;
305 j++;
307 if (j == 0)
308 return (NULL);
310 algname[j] = '\0';
312 return (strdup(algname));
317 * log_invalid_policy - syslog helper
319 static void
320 log_invalid_policy(enum crypt_policy_error_e error, char *value)
322 switch (error) {
323 case CPE_BOTH:
324 syslog(LOG_AUTH | LOG_ERR,
325 "crypt(3c): %s contains both %s and %s; only one may be "
326 "specified, using first entry in file.", POLICY_CONF_FILE,
327 CRYPT_ALGORITHMS_ALLOW, CRYPT_ALGORITHMS_DEPRECATE);
328 break;
329 case CPE_MULTI:
330 syslog(LOG_AUTH | LOG_ERR,
331 "crypt(3c): %s contains multiple %s entries;"
332 "using first entry file.", POLICY_CONF_FILE, value);
333 break;
337 static char *
338 getval(const char *ival)
340 char *tmp;
341 char *oval;
342 int off;
344 if (ival == NULL)
345 return (NULL);
347 if ((tmp = strchr(ival, '=')) == NULL)
348 return (NULL);
350 oval = strdup(tmp + 1); /* everything after the "=" */
351 if (oval == NULL)
352 return (NULL);
353 off = strlen(oval) - 1;
354 if (off < 0) {
355 free(oval);
356 return (NULL);
358 if (oval[off] == '\n')
359 oval[off] = '\0';
361 return (oval);
365 * getcryptpolicy - read /etc/security/policy.conf into a crypt_policy_s
367 static struct crypt_policy_s *
368 getcryptpolicy(void)
370 FILE *pconf;
371 char line[BUFSIZ];
372 struct crypt_policy_s *policy;
374 if ((pconf = fopen(POLICY_CONF_FILE, "rF")) == NULL) {
375 return (NULL);
378 policy = malloc(sizeof (struct crypt_policy_s));
379 if (policy == NULL) {
380 return (NULL);
382 policy->cp_default = NULL;
383 policy->cp_allow = NULL;
384 policy->cp_deny = NULL;
386 while (!feof(pconf) &&
387 (fgets(line, sizeof (line), pconf) != NULL)) {
388 if (strncasecmp(CRYPT_DEFAULT, line,
389 strlen(CRYPT_DEFAULT)) == 0) {
390 if (policy->cp_default != NULL) {
391 log_invalid_policy(CPE_MULTI, CRYPT_DEFAULT);
392 } else {
393 policy->cp_default = getval(line);
396 if (strncasecmp(CRYPT_ALGORITHMS_ALLOW, line,
397 strlen(CRYPT_ALGORITHMS_ALLOW)) == 0) {
398 if (policy->cp_deny != NULL) {
399 log_invalid_policy(CPE_BOTH, NULL);
400 } else if (policy->cp_allow != NULL) {
401 log_invalid_policy(CPE_MULTI,
402 CRYPT_ALGORITHMS_ALLOW);
403 } else {
404 policy->cp_allow = getval(line);
407 if (strncasecmp(CRYPT_ALGORITHMS_DEPRECATE, line,
408 strlen(CRYPT_ALGORITHMS_DEPRECATE)) == 0) {
409 if (policy->cp_allow != NULL) {
410 log_invalid_policy(CPE_BOTH, NULL);
411 } else if (policy->cp_deny != NULL) {
412 log_invalid_policy(CPE_MULTI,
413 CRYPT_ALGORITHMS_DEPRECATE);
414 } else {
415 policy->cp_deny = getval(line);
419 (void) fclose(pconf);
421 if (policy->cp_default == NULL) {
422 policy->cp_default = strdup(CRYPT_UNIX);
423 if (policy->cp_default == NULL)
424 free_crypt_policy(policy);
427 return (policy);
432 * alg_valid - is this algorithm valid given the policy ?
434 static boolean_t
435 alg_valid(const char *algname, const struct crypt_policy_s *policy)
437 char *lasts;
438 char *list;
439 char *entry;
440 boolean_t allowed = B_FALSE;
442 if ((algname == NULL) || (policy == NULL)) {
443 return (B_FALSE);
446 if (strcmp(algname, policy->cp_default) == 0) {
447 return (B_TRUE);
450 if (policy->cp_deny != NULL) {
451 list = policy->cp_deny;
452 allowed = B_FALSE;
453 } else if (policy->cp_allow != NULL) {
454 list = policy->cp_allow;
455 allowed = B_TRUE;
456 } else {
458 * Neither of allow or deny policies are set so anything goes.
460 return (B_TRUE);
462 lasts = list;
463 while ((entry = strtok_r(NULL, ",", &lasts)) != NULL) {
464 if (strcmp(entry, algname) == 0) {
465 return (allowed);
469 return (!allowed);
473 * getalgbyname - read crypt.conf(4) looking for algname
475 * RETURN VALUES
476 * On error NULL and errno is set
477 * On success the alg details including an open handle to the lib
478 * If crypt.conf(4) is okay but algname doesn't exist in it then
479 * return NULL the caller should then use the default algorithm
480 * as per the policy.
482 static struct crypt_alg_s *
483 getalgbyname(const char *algname, boolean_t *found)
485 struct stat stb;
486 int configfd;
487 FILE *fconf = NULL;
488 struct crypt_alg_s *alg = NULL;
489 char line[CRYPT_CONFLINELENGTH];
490 int linelen = 0;
491 int lineno = 0;
492 char *pathname = NULL;
493 char *lasts = NULL;
494 char *token = NULL;
496 *found = B_FALSE;
497 if ((algname == NULL) || (strcmp(algname, CRYPT_UNIX) == 0)) {
498 return (NULL);
501 if ((configfd = open(CRYPT_CONFFILE, O_RDONLY)) == -1) {
502 syslog(LOG_ALERT, "crypt: open(%s) failed: %s",
503 CRYPT_CONFFILE, strerror(errno));
504 return (NULL);
508 * Stat the file so we can check modes and ownerships
510 if (fstat(configfd, &stb) < 0) {
511 syslog(LOG_ALERT, "crypt: stat(%s) failed: %s",
512 CRYPT_CONFFILE, strerror(errno));
513 goto cleanup;
517 * Check the ownership of the file
519 if (stb.st_uid != (uid_t)0) {
520 syslog(LOG_ALERT,
521 "crypt: Owner of %s is not root", CRYPT_CONFFILE);
522 goto cleanup;
526 * Check the modes on the file
528 if (stb.st_mode & S_IWGRP) {
529 syslog(LOG_ALERT,
530 "crypt: %s writable by group", CRYPT_CONFFILE);
531 goto cleanup;
533 if (stb.st_mode & S_IWOTH) {
534 syslog(LOG_ALERT,
535 "crypt: %s writable by world", CRYPT_CONFFILE);
536 goto cleanup;
539 if ((fconf = fdopen(configfd, "rF")) == NULL) {
540 syslog(LOG_ALERT, "crypt: fdopen(%d) failed: %s",
541 configfd, strerror(errno));
542 goto cleanup;
546 * /etc/security/crypt.conf has 3 fields:
547 * <algname> <pathname> [<name[=val]>[<name[=val]>]]
549 errno = 0;
550 while (!(*found) &&
551 ((fgets(line, sizeof (line), fconf) != NULL) && !feof(fconf))) {
552 lineno++;
554 * Skip over comments
556 if ((line[0] == '#') || (line[0] == '\n')) {
557 continue;
560 linelen = strlen(line);
561 line[--linelen] = '\0'; /* chop the trailing \n */
563 token = strtok_r(line, " \t", &lasts);
564 if (token == NULL) {
565 continue;
567 if (strcmp(token, algname) == 0) {
568 *found = B_TRUE;
571 if (!found) {
572 errno = EINVAL;
573 goto cleanup;
576 token = strtok_r(NULL, " \t", &lasts);
577 if (token == NULL) {
579 * Broken config file
581 syslog(LOG_ALERT, "crypt(3c): %s may be corrupt at line %d",
582 CRYPT_CONFFILE, lineno);
583 *found = B_FALSE;
584 errno = EINVAL;
585 goto cleanup;
588 if ((pathname = isa_path(token)) == NULL) {
589 if (errno != ENOMEM)
590 errno = EINVAL;
591 *found = B_FALSE;
592 goto cleanup;
595 if ((alg = malloc(sizeof (struct crypt_alg_s))) == NULL) {
596 *found = B_FALSE;
597 goto cleanup;
599 alg->a_libhandle = NULL;
600 alg->a_genhash = NULL;
601 alg->a_gensalt = NULL;
602 alg->a_params = NULL;
603 alg->a_nparams = 0;
606 * The rest of the line is module specific params, space
607 * seprated. We wait until after we have checked the module is
608 * valid before parsing them into a_params, this saves us
609 * having to free them later if there is a problem.
611 if ((alg->a_libhandle = dlopen(pathname, RTLD_NOW)) == NULL) {
612 syslog(LOG_ERR, "crypt(3c) unable to dlopen %s: %s",
613 pathname, dlerror());
614 errno = ELIBACC;
615 *found = B_FALSE;
616 goto cleanup;
619 alg->a_genhash =
620 (char *(*)())dlsym(alg->a_libhandle, "crypt_genhash_impl");
621 if (alg->a_genhash == NULL) {
622 syslog(LOG_ERR, "crypt(3c) unable to find cryp_genhash_impl"
623 "symbol in %s: %s", pathname, dlerror());
624 errno = ELIBACC;
625 *found = B_FALSE;
626 goto cleanup;
628 alg->a_gensalt =
629 (char *(*)())dlsym(alg->a_libhandle, "crypt_gensalt_impl");
630 if (alg->a_gensalt == NULL) {
631 syslog(LOG_ERR, "crypt(3c) unable to find crypt_gensalt_impl"
632 "symbol in %s: %s", pathname, dlerror());
633 errno = ELIBACC;
634 *found = B_FALSE;
635 goto cleanup;
639 * We have a good module so build the a_params if we have any.
640 * Count how much space we need first and then allocate an array
641 * to hold that many module params.
643 if (lasts != NULL) {
644 int nparams = 0;
645 char *tparams;
646 char *tplasts;
648 if ((tparams = strdup(lasts)) == NULL) {
649 *found = B_FALSE;
650 goto cleanup;
653 (void) strtok_r(tparams, " \t", &tplasts);
654 do {
655 nparams++;
656 } while (strtok_r(NULL, " \t", &tplasts) != NULL);
657 free(tparams);
659 alg->a_params = calloc(nparams + 1, sizeof (char *));
660 if (alg->a_params == NULL) {
661 *found = B_FALSE;
662 goto cleanup;
665 while ((token = strtok_r(NULL, " \t", &lasts)) != NULL) {
666 alg->a_params[alg->a_nparams++] = token;
670 cleanup:
671 if (*found == B_FALSE) {
672 free_crypt_alg(alg);
673 alg = NULL;
676 if (pathname != NULL) {
677 free(pathname);
680 if (fconf != NULL) {
681 (void) fclose(fconf);
682 } else {
683 (void) close(configfd);
686 return (alg);
689 static void
690 free_crypt_alg(struct crypt_alg_s *alg)
692 if (alg == NULL)
693 return;
695 if (alg->a_libhandle != NULL) {
696 (void) dlclose(alg->a_libhandle);
698 if (alg->a_nparams != 0) {
699 free(alg->a_params);
701 free(alg);
704 static void
705 free_crypt_policy(struct crypt_policy_s *policy)
707 if (policy == NULL)
708 return;
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;
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;
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;
728 free(policy);
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.
736 static char *
737 isa_path(const char *path)
739 char *ret = NULL;
741 if ((path == NULL) || (strlen(path) > PATH_MAX)) {
742 return (NULL);
745 ret = calloc(PATH_MAX, sizeof (char));
748 * Module path doesn't start with "/" then prepend
749 * the default search path CRYPT_MODULE_DIR (/usr/lib/security/$ISA)
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);
757 } else { /* patch up $ISA */
758 char *isa;
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);
768 } else {
769 free(ret);
770 ret = strdup(path);
774 return (ret);
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[])
786 static const char saltchars[] =
787 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
788 struct timeval tv;
790 (void) gettimeofday(&tv, NULL);
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';
796 return (gsbuffer);
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.
804 * It is included here to reduce the overhead of dlopen()
805 * for the common case.
809 /* Copyright (c) 1988 AT&T */
810 /* All Rights Reserved */
815 * This program implements a data encryption algorithm to encrypt passwords.
818 static mutex_t crypt_lock = DEFAULTMUTEX;
819 #define TSDBUFSZ (66 + 16)
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,
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,
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,
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,
857 static const char shifts[] = {
858 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
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,
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,
875 static char C[28];
876 static char D[28];
877 static char *KS;
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,
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.
897 static int
898 allocate_KS(void)
900 char *ks;
901 int failed;
902 int assigned;
904 if (KS != NULL) { /* already allocated */
905 membar_consumer();
906 return (0);
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;
920 lmutex_unlock(&crypt_lock);
921 if (!assigned)
922 free(ks);
923 return (failed);
926 static void
927 unlocked_setkey(const char *key)
929 int i, j, k;
930 char t;
932 for (i = 0; i < 28; i++) {
933 C[i] = key[PC1_C[i]-1];
934 D[i] = key[PC1_D[i]-1];
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;
947 for (j = 0; j < 24; j++) {
948 int index = i * 48;
950 *(KS+index+j) = C[PC2_C[j]-1];
951 *(KS+index+j+24) = D[PC2_D[j]-28-1];
954 for (i = 0; i < 48; i++)
955 E[i] = e2[i];
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,
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,
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,
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,
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,
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,
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,
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,
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,
1011 static char L[64];
1012 static char tempL[32];
1013 static char f[32];
1015 static char preS[48];
1017 /*ARGSUSED*/
1018 static void
1019 unlocked_encrypt(char *block, int fake)
1021 int i;
1022 int t, j, k;
1023 char *R = &L[32];
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;
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;
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];
1053 for (j = 0; j < 32; j++) {
1054 t = L[j];
1055 L[j] = R[j];
1056 R[j] = (char)t;
1058 for (j = 0; j < 64; j++)
1059 block[j] = L[FP[j]-1];
1062 char *
1063 _unix_crypt(const char *pw, const char *salt, char *iobuf)
1065 int c, i, j;
1066 char temp;
1067 char *block;
1069 block = iobuf + 16;
1071 if (iobuf == 0) {
1072 errno = ENOMEM;
1073 return (NULL);
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++;
1086 unlocked_setkey(block);
1088 for (i = 0; i < 66; i++)
1089 block[i] = 0;
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;
1108 for (i = 0; i < 25; i++)
1109 unlocked_encrypt(block, 0);
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];
1118 c += '.';
1119 if (c > '9')
1120 c += 7;
1121 if (c > 'Z')
1122 c += 6;
1123 iobuf[i+2] = (char)c;
1125 iobuf[i+2] = 0;
1126 if (iobuf[1] == 0)
1127 iobuf[1] = iobuf[0];
1128 return (iobuf);
1132 /*ARGSUSED*/
1133 void
1134 encrypt(char *block, int fake)
1136 if (fake != 0) {
1137 errno = ENOSYS;
1138 return;
1140 if (allocate_KS() != 0)
1141 return;
1142 lmutex_lock(&crypt_lock);
1143 unlocked_encrypt(block, fake);
1144 lmutex_unlock(&crypt_lock);
1148 void
1149 setkey(const char *key)
1151 if (allocate_KS() != 0)
1152 return;
1153 lmutex_lock(&crypt_lock);
1154 unlocked_setkey(key);
1155 lmutex_unlock(&crypt_lock);