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