]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_pgp.c
Alternate libgcrypt support for uams_pgp.
[netatalk.git] / etc / uams / uams_pgp.c
1 /*
2  * $Id: uams_pgp.c,v 1.10 2003-06-11 07:26:50 srittau Exp $
3  *
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.
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif /* HAVE_CONFIG_H */
12
13 #ifdef UAM_PGP
14
15 /* for crypt() */
16 #define _XOPEN_SOURCE
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif /* HAVE_UNISTD_H */
23 #include <pwd.h>
24 #include <atalk/logger.h>
25
26 #if defined(GNUTLS_DHX)
27 #include <gnutls/openssl.h>
28 #elif defined(OPENSSL_DHX)
29 #include <openssl/bn.h>
30 #include <openssl/dh.h>
31 #include <openssl/cast.h>
32 #else /* OPENSSL_DHX */
33 #include <bn.h>
34 #include <dh.h>
35 #include <cast.h>
36 #endif /* OPENSSL_DHX */
37
38 #include <atalk/afp.h>
39 #include <atalk/uam.h>
40
41 #define KEYSIZE 16
42 #define PASSWDLEN 64
43 #define CRYPTBUFLEN  (KEYSIZE*2)
44 #define CRYPT2BUFLEN (KEYSIZE + PASSWDLEN)
45
46 /* hash a number to a 16-bit quantity */
47 #define pgphash(a) ((((unsigned long) (a) >> 8) ^ \
48                      (unsigned long) (a)) & 0xffff)
49
50 /* the secret key */
51 static struct passwd *pgppwd;
52 static CAST_KEY castkey;
53 static u_int8_t randbuf[16];
54
55 /* pgp passwd */
56 static int pgp_login(void *obj, struct passwd **uam_pwd,
57                      char *ibuf, int ibuflen,
58                      char *rbuf, int *rbuflen)
59 {
60     BIGNUM *bn, *gbn, *pbn;
61     u_int16_t sessid;
62     int len, i;
63     char *name;
64
65     *rbuflen = 0;
66
67     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &name, &i) < 0)
68       return AFPERR_PARAM;
69
70     len = (unsigned char) *ibuf++;
71     if ( len > i ) {
72         return( AFPERR_PARAM );
73     }
74
75     memcpy(name, ibuf, len );
76     ibuf += len;
77     name[ len ] = '\0';
78     if ((unsigned long) ibuf & 1) /* padding */
79       ++ibuf;
80
81     if (( pgppwd = uam_getname(name, i)) == NULL ) {
82       return AFPERR_PARAM;
83     }
84
85     LOG(log_info, logtype_uams, "pgp login: %s", name);
86     if (uam_checkuser(pgppwd) < 0)
87       return AFPERR_NOTAUTH;
88
89     /* get the challenge */
90     len = (unsigned char) *ibuf++;
91     /* challenge */
92     
93     /* get the signature. it's always 16 bytes. */
94     if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE, 
95                              (void *) &name, NULL) < 0) {
96       *rbuflen = 0;
97       goto pgp_fail;
98     }
99     memcpy(rbuf + KEYSIZE, name, KEYSIZE); 
100
101 pgp_fail:
102     return AFPERR_PARAM;
103 }
104
105 static int pgp_logincont(void *obj, struct passwd **uam_pwd,
106                          char *ibuf, int ibuflen, 
107                          char *rbuf, int *rbuflen)
108 {
109     unsigned char iv[] = "RJscorat";
110 #ifdef HAVE_GCRYPT
111     GcryMPI *bn1, *bn2, *bn3;
112 #else /* HAVE_GCRYPT */
113     BIGNUM *bn1, *bn2, *bn3;
114 #endif
115     u_int16_t sessid;
116     char *p;
117
118     *rbuflen = 0;
119
120     /* check for session id */
121     memcpy(&sessid, ibuf, sizeof(sessid));
122     if (sessid != pgphash(obj))
123       return AFPERR_PARAM;
124     ibuf += sizeof(sessid);
125
126 #ifdef HAVE_GCRYPT
127     {
128       GcryCipherHd handle;
129
130       handle = gcry_cipher_open(GCRY_CIPHER_CAST5,
131                                       GCRY_CIPHER_MODE_CBC, 0);
132       if (!handle)
133         return AFPERR_PARAM;
134
135       if (gcry_cipher_setkey(handle, &castkey, ) != 0) {
136         gcry_cipher_close(handle);
137         return AFPERR_PARAM;
138       }
139
140       if (gcry_cipher_setiv(handle, iv, sizeof(iv)) != 0) {
141         gcry_cipher_close(handle);
142         return AFPERR_PARAM;
143       }
144
145       if (gcry_cipher_decrypt(handle, rbuf, CRYPT2BUFLEN, ibuf, CRYPT2BUFLEN) != 0) {
146         gcry_cipher_close(handle);
147         return AFPERR_PARAM;
148       }
149
150       gcry_cipher_close(handle);
151     }
152 #else /* HAVE_GCRYPT */
153     /* use rbuf as scratch space */
154     CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey,
155                      iv, CAST_DECRYPT);
156 #endif /* HAVE_GCRYPT */
157
158 #ifdef HAVE_GCRYPT
159     {
160       size_t sz;
161
162       bn1 = gcry_mpi_snew(KEYSIZE * 8);
163       sz = KEYSIZE;
164       gcry_mpi_scan(bn1, GCRYMPI_FMT_STD, rbuf, &sz);
165       bn2 = gcry_mpi_snew(sizeof(randbuf) * 8);
166       sz = sizeof(randbuf);
167       gcry_mpi_scan(bn1, GCRYMPI_FMT_STD, randbuf. &sz);
168     }
169 #else /* HAVE_GCRYPT */
170     /* check to make sure that the random number is the same. we
171      * get sent back an incremented random number. */
172     if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL)))
173       return AFPERR_PARAM;
174
175     if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) {
176       BN_free(bn1);
177       return AFPERR_PARAM;
178     }
179 #endif /* HAVE_GCRYPT */
180
181     /* zero out the random number */
182     memset(rbuf, 0, sizeof(randbuf));
183     memset(randbuf, 0, sizeof(randbuf));
184     rbuf += KEYSIZE;
185
186 #ifdef HAVE_GCRYPT
187     bn3 = gcry_mpi_snew(0);
188     gcry_mpi_sub(bn3, bn1, bn2);
189     gcry_mpi_release(bn2);
190     gcry_mpi_release(bn1);
191
192     if (gcry_mpi_cmp_ui(bn3, 1UL) != 0) {
193       gcry_mpi_release(bn3);
194       return AFPERR_PARAM;
195     }
196     gcry_mpi_release(bn3);
197 #else /* HAVE_GCRYPT */
198     if (!(bn3 = BN_new())) {
199       BN_free(bn2);
200       BN_free(bn1);
201       return AFPERR_PARAM;
202     }
203
204     BN_sub(bn3, bn1, bn2);
205     BN_free(bn2);
206     BN_free(bn1);
207
208     /* okay. is it one more? */
209     if (!BN_is_one(bn3)) {
210       BN_free(bn3);
211       return AFPERR_PARAM;
212     }
213     BN_free(bn3);
214 #endif /* HAVE_GCRYPT */
215
216 #ifdef AFS
217     if ( kcheckuser(*uam_pwd, rbuf) == 0) {
218       *uam_pwd = pgppwd;
219       return AFP_OK;
220     }
221 #endif /* AFS */
222
223     rbuf[PASSWDLEN] = '\0';
224     p = crypt( rbuf, pgppwd->pw_passwd );
225     memset(rbuf, 0, PASSWDLEN);
226     if ( strcmp( p, pgppwd->pw_passwd ) == 0 ) {
227       *uam_pwd = pgppwd;
228       return AFP_OK;
229     }
230
231     return AFPERR_NOTAUTH;
232 }
233
234
235 static int uam_setup(const char *path)
236 {
237   if (uam_register(UAM_SERVER_LOGIN, path, "PGPuam 1.0",
238                    pgp_login, pgp_logincont, NULL) < 0)
239     return -1;
240
241   return 0;
242 }
243
244 static void uam_cleanup(void)
245 {
246   uam_unregister(UAM_SERVER_LOGIN, "PGPuam 1.0");
247 }
248
249 UAM_MODULE_EXPORT struct uam_export uams_pgp = {
250   UAM_MODULE_SERVER,
251   UAM_MODULE_VERSION,
252   uam_setup, uam_cleanup
253 };
254
255 #endif /* UAM_PGP */