2 * $Id: uams_pgp.c,v 1.12 2009-10-15 11:39:48 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
6 * All Rights Reserved. See COPYRIGHT.
11 #endif /* HAVE_CONFIG_H */
22 #endif /* HAVE_UNISTD_H */
25 #endif /* HAVE_CRYPT_H */
27 #include <atalk/logger.h>
29 #if defined(GNUTLS_DHX)
30 #include <gnutls/openssl.h>
31 #elif defined(OPENSSL_DHX)
32 #include <openssl/bn.h>
33 #include <openssl/dh.h>
34 #include <openssl/cast.h>
35 #else /* OPENSSL_DHX */
39 #endif /* OPENSSL_DHX */
41 #include <atalk/afp.h>
42 #include <atalk/uam.h>
46 #define CRYPTBUFLEN (KEYSIZE*2)
47 #define CRYPT2BUFLEN (KEYSIZE + PASSWDLEN)
49 /* hash a number to a 16-bit quantity */
50 #define pgphash(a) ((((unsigned long) (a) >> 8) ^ \
51 (unsigned long) (a)) & 0xffff)
54 static struct passwd *pgppwd;
55 static CAST_KEY castkey;
56 static u_int8_t randbuf[16];
59 static int pgp_login(void *obj, struct passwd **uam_pwd,
60 char *ibuf, size_t ibuflen,
61 char *rbuf, size_t *rbuflen)
68 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &name, &i) < 0)
71 len = (unsigned char) *ibuf++;
73 return( AFPERR_PARAM );
76 memcpy(name, ibuf, len );
79 if ((unsigned long) ibuf & 1) /* padding */
82 if (( pgppwd = uam_getname(obj, name, i)) == NULL ) {
86 LOG(log_info, logtype_uams, "pgp login: %s", name);
87 if (uam_checkuser(pgppwd) < 0)
88 return AFPERR_NOTAUTH;
90 /* get the challenge */
91 len = (unsigned char) *ibuf++;
94 /* get the signature. it's always 16 bytes. */
95 if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE,
96 (void *) &name, NULL) < 0) {
100 memcpy(rbuf + KEYSIZE, name, KEYSIZE);
106 static int pgp_logincont(void *obj, struct passwd **uam_pwd,
107 char *ibuf, size_t ibuflen,
108 char *rbuf, size_t *rbuflen)
110 unsigned char iv[] = "RJscorat";
111 BIGNUM *bn1, *bn2, *bn3;
117 /* check for session id */
118 memcpy(&sessid, ibuf, sizeof(sessid));
119 if (sessid != pgphash(obj))
121 ibuf += sizeof(sessid);
123 /* use rbuf as scratch space */
124 CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey,
127 /* check to make sure that the random number is the same. we
128 * get sent back an incremented random number. */
129 if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL)))
132 if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) {
137 /* zero out the random number */
138 memset(rbuf, 0, sizeof(randbuf));
139 memset(randbuf, 0, sizeof(randbuf));
142 if (!(bn3 = BN_new())) {
148 BN_sub(bn3, bn1, bn2);
152 /* okay. is it one more? */
153 if (!BN_is_one(bn3)) {
160 if ( kcheckuser(*uam_pwd, rbuf) == 0) {
166 rbuf[PASSWDLEN] = '\0';
167 p = crypt( rbuf, pgppwd->pw_passwd );
168 memset(rbuf, 0, PASSWDLEN);
169 if ( strcmp( p, pgppwd->pw_passwd ) == 0 ) {
174 return AFPERR_NOTAUTH;
178 static int uam_setup(const char *path)
180 if (uam_register(UAM_SERVER_LOGIN, path, "PGPuam 1.0",
181 pgp_login, pgp_logincont, NULL) < 0)
187 static void uam_cleanup(void)
189 uam_unregister(UAM_SERVER_LOGIN, "PGPuam 1.0");
192 UAM_MODULE_EXPORT struct uam_export uams_pgp = {
195 uam_setup, uam_cleanup