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