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