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 */ 54static struct passwd *pgppwd; 55static CAST_KEY castkey; 56static u_int8_t randbuf[16]; 57 58/* pgp passwd */ 59static 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 102pgp_fail: 103 return AFPERR_PARAM; 104} 105 106static 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 178static 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 187static void uam_cleanup(void) 188{ 189 uam_unregister(UAM_SERVER_LOGIN, "PGPuam 1.0"); 190} 191 192UAM_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 */ 199