]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_pgp.c
6a2994401c493d5cadd33a5f86161904d17f644c
[netatalk.git] / etc / uams / uams_pgp.c
1 /*
2  *
3  * Copyright (c) 1990,1993 Regents of The University of Michigan.
4  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #ifdef UAM_PGP
13
14 #include <atalk/standards.h>
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif /* HAVE_UNISTD_H */
22 #ifdef HAVE_CRYPT_H
23 #include <crypt.h>
24 #endif /* HAVE_CRYPT_H */
25 #include <pwd.h>
26 #include <atalk/logger.h>
27
28 #if defined(GNUTLS_DHX)
29 #include <gnutls/openssl.h>
30 #elif defined(OPENSSL_DHX)
31 #include <openssl/bn.h>
32 #include <openssl/dh.h>
33 #include <openssl/cast.h>
34 #else /* OPENSSL_DHX */
35 #include <bn.h>
36 #include <dh.h>
37 #include <cast.h>
38 #endif /* OPENSSL_DHX */
39
40 #include <atalk/afp.h>
41 #include <atalk/uam.h>
42
43 #define KEYSIZE 16
44 #define PASSWDLEN 64
45 #define CRYPTBUFLEN  (KEYSIZE*2)
46 #define CRYPT2BUFLEN (KEYSIZE + PASSWDLEN)
47
48 /* hash a number to a 16-bit quantity */
49 #define pgphash(a) ((((unsigned long) (a) >> 8) ^ \
50                      (unsigned long) (a)) & 0xffff)
51
52 /* the secret key */
53 static struct passwd *pgppwd;
54 static CAST_KEY castkey;
55 static uint8_t randbuf[16];
56
57 /* pgp passwd */
58 static int pgp_login(void *obj, struct passwd **uam_pwd,
59                      char *ibuf, size_t ibuflen,
60                      char *rbuf, size_t *rbuflen)
61 {
62     size_t 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(obj, 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, size_t ibuflen, 
107                          char *rbuf, size_t *rbuflen)
108 {
109         unsigned char iv[] = "RJscorat";
110     BIGNUM *bn1, *bn2, *bn3;
111     uint16_t sessid;
112     char *p;
113
114     *rbuflen = 0;
115
116     /* check for session id */
117     memcpy(&sessid, ibuf, sizeof(sessid));
118     if (sessid != pgphash(obj))
119       return AFPERR_PARAM;
120     ibuf += sizeof(sessid);
121    
122     /* use rbuf as scratch space */
123     CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey,
124                      iv, CAST_DECRYPT);
125     
126     /* check to make sure that the random number is the same. we
127      * get sent back an incremented random number. */
128     if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL)))
129       return AFPERR_PARAM;
130
131     if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) {
132       BN_free(bn1);
133       return AFPERR_PARAM;
134     }
135       
136     /* zero out the random number */
137     memset(rbuf, 0, sizeof(randbuf));
138     memset(randbuf, 0, sizeof(randbuf));
139     rbuf += KEYSIZE;
140
141     if (!(bn3 = BN_new())) {
142       BN_free(bn2);
143       BN_free(bn1);
144       return AFPERR_PARAM;
145     }
146
147     BN_sub(bn3, bn1, bn2);
148     BN_free(bn2);
149     BN_free(bn1);
150
151     /* okay. is it one more? */
152     if (!BN_is_one(bn3)) {
153       BN_free(bn3);
154       return AFPERR_PARAM;
155     }
156     BN_free(bn3);
157
158 #ifdef AFS
159     if ( kcheckuser(*uam_pwd, rbuf) == 0) {
160       *uam_pwd = pgppwd;
161       return AFP_OK;
162     }
163 #endif /* AFS */
164
165     rbuf[PASSWDLEN] = '\0';
166     p = crypt( rbuf, pgppwd->pw_passwd );
167     memset(rbuf, 0, PASSWDLEN);
168     if ( strcmp( p, pgppwd->pw_passwd ) == 0 ) {
169       *uam_pwd = pgppwd;
170       return AFP_OK;
171     }
172
173     return AFPERR_NOTAUTH;
174 }
175
176
177 static int uam_setup(const char *path)
178 {
179   if (uam_register(UAM_SERVER_LOGIN, path, "PGPuam 1.0",
180                    pgp_login, pgp_logincont, NULL) < 0)
181     return -1;
182
183   return 0;
184 }
185
186 static void uam_cleanup(void)
187 {
188   uam_unregister(UAM_SERVER_LOGIN, "PGPuam 1.0");
189 }
190
191 UAM_MODULE_EXPORT struct uam_export uams_pgp = {
192   UAM_MODULE_SERVER,
193   UAM_MODULE_VERSION,
194   uam_setup, uam_cleanup
195 };
196
197 #endif /* UAM_PGP */