]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_pgp.c
Don't assume offsets, specify the struct member. (Olaf)
[netatalk.git] / etc / uams / uams_pgp.c
1 /*
2  * $Id: uams_pgp.c,v 1.8 2003-01-26 16:40:45 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 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif /* HAVE_UNISTD_H */
21 #include <pwd.h>
22 #include <atalk/logger.h>
23
24 #if defined(GNUTLS_DHX)
25 #include <gnutls/openssl.h>
26 #elif defined(OPENSSL_DHX)
27 #include <openssl/bn.h>
28 #include <openssl/dh.h>
29 #include <openssl/cast.h>
30 #else /* OPENSSL_DHX */
31 #include <bn.h>
32 #include <dh.h>
33 #include <cast.h>
34 #endif /* OPENSSL_DHX */
35
36 #include <atalk/afp.h>
37 #include <atalk/uam.h>
38
39 #define KEYSIZE 16
40 #define PASSWDLEN 64
41 #define CRYPTBUFLEN  (KEYSIZE*2)
42 #define CRYPT2BUFLEN (KEYSIZE + PASSWDLEN)
43
44 /* hash a number to a 16-bit quantity */
45 #define pgphash(a) ((((unsigned long) (a) >> 8) ^ \
46                      (unsigned long) (a)) & 0xffff)
47
48 /* the secret key */
49 static struct passwd *pgppwd;
50 static CAST_KEY castkey;
51 static u_int8_t randbuf[16];
52
53 /* pgp passwd */
54 static int pgp_login(void *obj, struct passwd **uam_pwd,
55                      char *ibuf, int ibuflen,
56                      char *rbuf, int *rbuflen)
57 {
58     BIGNUM *bn, *gbn, *pbn;
59     u_int16_t sessid;
60     int len, i;
61     char *name;
62
63     *rbuflen = 0;
64
65     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &name, &i) < 0)
66       return AFPERR_PARAM;
67
68     len = (unsigned char) *ibuf++;
69     if ( len > i ) {
70         return( AFPERR_PARAM );
71     }
72
73     memcpy(name, ibuf, len );
74     ibuf += len;
75     name[ len ] = '\0';
76     if ((unsigned long) ibuf & 1) /* padding */
77       ++ibuf;
78
79     if (( pgppwd = uam_getname(name, i)) == NULL ) {
80       return AFPERR_PARAM;
81     }
82
83     LOG(log_info, logtype_uams, "pgp login: %s", name);
84     if (uam_checkuser(pgppwd) < 0)
85       return AFPERR_NOTAUTH;
86
87     /* get the challenge */
88     len = (unsigned char) *ibuf++;
89     /* challenge */
90     
91     /* get the signature. it's always 16 bytes. */
92     if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE, 
93                              (void *) &name, NULL) < 0) {
94       *rbuflen = 0;
95       goto pgp_fail;
96     }
97     memcpy(rbuf + KEYSIZE, name, KEYSIZE); 
98
99 pgp_fail:
100     return AFPERR_PARAM;
101 }
102
103 static int pgp_logincont(void *obj, struct passwd **uam_pwd,
104                          char *ibuf, int ibuflen, 
105                          char *rbuf, int *rbuflen)
106 {
107         unsigned char iv[] = "RJscorat";
108     BIGNUM *bn1, *bn2, *bn3;
109     u_int16_t sessid;
110     char *p;
111
112     *rbuflen = 0;
113
114     /* check for session id */
115     memcpy(&sessid, ibuf, sizeof(sessid));
116     if (sessid != pgphash(obj))
117       return AFPERR_PARAM;
118     ibuf += sizeof(sessid);
119    
120     /* use rbuf as scratch space */
121     CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey,
122                      iv, CAST_DECRYPT);
123     
124     /* check to make sure that the random number is the same. we
125      * get sent back an incremented random number. */
126     if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL)))
127       return AFPERR_PARAM;
128
129     if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) {
130       BN_free(bn1);
131       return AFPERR_PARAM;
132     }
133       
134     /* zero out the random number */
135     memset(rbuf, 0, sizeof(randbuf));
136     memset(randbuf, 0, sizeof(randbuf));
137     rbuf += KEYSIZE;
138
139     if (!(bn3 = BN_new())) {
140       BN_free(bn2);
141       BN_free(bn1);
142       return AFPERR_PARAM;
143     }
144
145     BN_sub(bn3, bn1, bn2);
146     BN_free(bn2);
147     BN_free(bn1);
148
149     /* okay. is it one more? */
150     if (!BN_is_one(bn3)) {
151       BN_free(bn3);
152       return AFPERR_PARAM;
153     }
154     BN_free(bn3);
155
156 #ifdef AFS
157     if ( kcheckuser(*uam_pwd, rbuf) == 0) {
158       *uam_pwd = pgppwd;
159       return AFP_OK;
160     }
161 #endif /* AFS */
162
163     rbuf[PASSWDLEN] = '\0';
164     p = crypt( rbuf, pgppwd->pw_passwd );
165     memset(rbuf, 0, PASSWDLEN);
166     if ( strcmp( p, pgppwd->pw_passwd ) == 0 ) {
167       *uam_pwd = pgppwd;
168       return AFP_OK;
169     }
170
171     return AFPERR_NOTAUTH;
172 }
173
174
175 static int uam_setup(const char *path)
176 {
177   if (uam_register(UAM_SERVER_LOGIN, path, "PGPuam 1.0",
178                    pgp_login, pgp_logincont, NULL) < 0)
179     return -1;
180
181   return 0;
182 }
183
184 static void uam_cleanup(void)
185 {
186   uam_unregister(UAM_SERVER_LOGIN, "PGPuam 1.0");
187 }
188
189 UAM_MODULE_EXPORT struct uam_export uams_pgp = {
190   UAM_MODULE_SERVER,
191   UAM_MODULE_VERSION,
192   uam_setup, uam_cleanup
193 };
194
195 #endif /* UAM_PGP */