mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
Update head to match stable 1.0
This commit is contained in:
parent
98a05e4239
commit
151ee2f47b
154 changed files with 29296 additions and 1324 deletions
116
keyserver/ChangeLog
Normal file
116
keyserver/ChangeLog
Normal file
|
@ -0,0 +1,116 @@
|
|||
2002-06-11 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* Makefile.am: Don't hard-code the LDAP libraries - get them from
|
||||
LDAPLIBS via configure. Also, gpgkeys_hkp is a program, not a
|
||||
script.
|
||||
|
||||
2002-06-10 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_ldap.c (include_subkeys): Default "include-subkeys" to
|
||||
off, since GnuPG now defaults it to on.
|
||||
|
||||
2002-06-06 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_hkp.c (parse_hkp_index): Type tweaks.
|
||||
|
||||
* gpgkeys_hkp.c (main): Add experimental code warning.
|
||||
|
||||
2002-06-05 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* Makefile.am, gpgkeys_hkp.c (new): Experimental HKP keyserver
|
||||
interface.
|
||||
|
||||
2002-05-08 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_ldap.c: Include <lber.h> if we absolutely must. This
|
||||
helps when compiling against a very old OpenLDAP.
|
||||
|
||||
2002-04-29 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_mailto.in: Properly handle key requests in full
|
||||
fingerprint form.
|
||||
|
||||
2002-03-29 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_ldap.c (printquoted): Quote backslashes within keyserver
|
||||
search responses.
|
||||
|
||||
2002-02-25 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_ldap (get_key): LDAP keyservers do not support v3
|
||||
fingerprints, so error out if someone tries. Actually, they don't
|
||||
support any fingerprints, but at least we can calculate a keyid
|
||||
from a v4 fingerprint.
|
||||
|
||||
2002-02-23 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_ldap: Clarify the notion of a partial failure. This is
|
||||
possible if more than one key is being handled in a batch, and one
|
||||
fails while the other succeeds. Note that a search that comes up
|
||||
with no results is not a failure - that is a valid response of "no
|
||||
answer".
|
||||
|
||||
* gpgkeys_ldap.c (get_key): Allow GnuPG to send us full v4
|
||||
fingerprints, long key ids, or short key ids while fetching.
|
||||
Since the LDAP server doesn't actually handle fingerprints, chop
|
||||
them down to long key ids for actual use.
|
||||
|
||||
* gpgkeys_ldap.c (main, get_key): When searching for a keyid,
|
||||
search for subkeys as well as primary keys. This is mostly
|
||||
significant when automatically fetching the key based on the id in
|
||||
a header (i.e. "signature made by...."). "no-include-subkeys"
|
||||
disables.
|
||||
|
||||
2002-02-14 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_ldap.c: Fix compiler warning.
|
||||
|
||||
* gpgkeys_ldap.c: Be much more robust with mangled input files.
|
||||
|
||||
2001-12-28 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_mailto.in: Use the new OUTOFBAND indicator so gpg knows
|
||||
not to try and import anything. Also turn on perl -w for
|
||||
warnings.
|
||||
|
||||
* gpgkeys_ldap.c (main): If we're using temp files (rather than
|
||||
stdin/stdout), make sure the file is closed when we're done.
|
||||
|
||||
2001-12-20 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* Properly free the LDAP response when we're done with it.
|
||||
|
||||
* Now that we handle multiple keys, we must remove duplicates as
|
||||
the LDAP keyserver returns keys with multiple user IDs multiple
|
||||
times.
|
||||
|
||||
* Properly handle multiple keys with the same key ID (it's really
|
||||
rare, so fetch "0xDEADBEEF" to test this).
|
||||
|
||||
2001-12-17 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_ldap.c, gpgkeys_mailto.in: Fix GNU capitalization
|
||||
issues. Prefix log messages with "gpgkeys" to clarify which
|
||||
program is generating them.
|
||||
|
||||
2001-12-14 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* gpgkeys_ldap.c (search_key): Use unsigned int rather than uint
|
||||
for portability.
|
||||
|
||||
2001-12-04 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* Initial version of gpgkeys_ldap (LDAP keyserver helper) and
|
||||
gpgkeys_mailto (email keyserver helper)
|
||||
|
||||
|
||||
Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is free software; as a special exception the author gives
|
||||
unlimited permission to copy and/or distribute it, with or without
|
||||
modifications, as long as this notice is preserved.
|
||||
|
||||
This file is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
36
keyserver/Makefile.am
Normal file
36
keyserver/Makefile.am
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GnuPG.
|
||||
#
|
||||
# GnuPG is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GnuPG is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include
|
||||
EXTRA_PROGRAMS = gpgkeys_ldap gpgkeys_hkp
|
||||
EXTRA_SCRIPTS = gpgkeys_mailto
|
||||
|
||||
# We don't need the libs the regular GPG binaries do
|
||||
LIBS=
|
||||
|
||||
bin_PROGRAMS = @GPGKEYS_LDAP@ @GPGKEYS_HKP@
|
||||
bin_SCRIPTS = @GPGKEYS_MAILTO@
|
||||
noinst_SCRIPTS = gpgkeys_test
|
||||
|
||||
# don't distribute hkp for now
|
||||
nodist_gpgkeys_hkp_SOURCES = gpgkeys_hkp.c
|
||||
|
||||
gpgkeys_ldap_LDADD = @LDAPLIBS@ @NETLIBS@
|
||||
gpgkeys_hkp_LDADD = @NETLIBS@
|
981
keyserver/gpgkeys_hkp.c
Normal file
981
keyserver/gpgkeys_hkp.c
Normal file
|
@ -0,0 +1,981 @@
|
|||
/* gpgkeys_hkp.c - talk to an HKP keyserver
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include "keyserver.h"
|
||||
|
||||
#define GET 0
|
||||
#define SEND 1
|
||||
#define SEARCH 2
|
||||
#define MAX_LINE 80
|
||||
|
||||
int verbose=0,include_disabled=0,include_revoked=0;
|
||||
char *basekeyspacedn=NULL;
|
||||
char host[80];
|
||||
FILE *input=NULL,*output=NULL,*console=NULL,*server=NULL;
|
||||
|
||||
struct keylist
|
||||
{
|
||||
char str[MAX_LINE];
|
||||
struct keylist *next;
|
||||
};
|
||||
|
||||
int http_connect(const char *host,unsigned short port)
|
||||
{
|
||||
int sock=-1;
|
||||
struct hostent *ent;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
sock=socket(AF_INET,SOCK_STREAM,0);
|
||||
if(sock==-1)
|
||||
{
|
||||
fprintf(console,"gpgkeys: internal socket error: %s\n",strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ent=gethostbyname(host);
|
||||
if(ent==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: DNS error: %s\n",hstrerror(h_errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
addr.sin_family=AF_INET;
|
||||
addr.sin_addr.s_addr=*(int *)ent->h_addr_list[0];
|
||||
addr.sin_port=htons(port?port:11371);
|
||||
|
||||
if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==-1)
|
||||
{
|
||||
fprintf(console,"gpgkeys: unable to contact keyserver: %s\n",
|
||||
strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
server=fdopen(sock,"r+");
|
||||
if(server==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: unable to fdopen socket: %s\n",
|
||||
strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(verbose>3)
|
||||
fprintf(console,"gpgkeys: HKP connect to %s:%d\n",host,port?port:11371);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if(sock>-1)
|
||||
close(sock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void http_disconnect(void)
|
||||
{
|
||||
if(verbose>3)
|
||||
fprintf(console,"gpgkeys: HKP disconnect from %s\n",host);
|
||||
|
||||
fclose(server);
|
||||
}
|
||||
|
||||
int http_get(const char *op,const char *search)
|
||||
{
|
||||
fprintf(server,"GET /pks/lookup?op=%s&search=%s HTTP/1.0\n\n",op,search);
|
||||
|
||||
if(verbose>2)
|
||||
fprintf(console,"gpgkeys: HTTP GET /pks/lookup?op=%s&search=%s HTTP/1.0\n",
|
||||
op,search);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_post(const char *data)
|
||||
{
|
||||
char line[MAX_LINE];
|
||||
int result;
|
||||
|
||||
fprintf(server,
|
||||
"POST /pks/add HTTP/1.0\n"
|
||||
"Content-type: application/x-www-form-urlencoded\n"
|
||||
"Content-Length: %d\n\n%s",strlen(data),data);
|
||||
|
||||
if(verbose>2)
|
||||
fprintf(console,
|
||||
"gpgkeys: HTTP POST /pks/add HTTP/1.0\n"
|
||||
"gpgkeys: Content-type: application/x-www-form-urlencoded\n"
|
||||
"gpgkeys: Content-Length: %d\n\n",strlen(data));
|
||||
|
||||
/* Now wait for a response */
|
||||
|
||||
while(fgets(line,MAX_LINE,server)!=NULL)
|
||||
if(sscanf(line,"HTTP/%*f %d OK",&result)==1)
|
||||
return result;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns 0 on success, -1 on failure, and 1 on eof */
|
||||
int send_key(void)
|
||||
{
|
||||
int err,gotit=0,keylen,maxlen,ret=-1;
|
||||
char keyid[17],line[MAX_LINE],*key;
|
||||
|
||||
key=strdup("keytext=");
|
||||
if(key==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: unable to allocate for key\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
maxlen=keylen=strlen(key);
|
||||
|
||||
/* Read and throw away stdin until we see the BEGIN */
|
||||
|
||||
while(fgets(line,MAX_LINE,input)!=NULL)
|
||||
if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1)
|
||||
{
|
||||
gotit=1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!gotit)
|
||||
{
|
||||
/* i.e. eof before the KEY BEGIN was found */
|
||||
ret=1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
gotit=0;
|
||||
|
||||
/* Now slurp up everything until we see the END */
|
||||
|
||||
while(fgets(line,MAX_LINE,input)!=NULL)
|
||||
if(sscanf(line,"KEY %16s END\n",keyid)==1)
|
||||
{
|
||||
gotit=1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *c=line;
|
||||
|
||||
while(*c!='\0')
|
||||
{
|
||||
if(maxlen-keylen<4)
|
||||
{
|
||||
maxlen+=1024;
|
||||
key=realloc(key,maxlen);
|
||||
if(key==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: unable to reallocate for key\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if(isalnum(*c) || *c=='-')
|
||||
{
|
||||
key[keylen++]=*c;
|
||||
key[keylen]='\0';
|
||||
}
|
||||
else if(*c==' ')
|
||||
{
|
||||
key[keylen++]='+';
|
||||
key[keylen]='\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(&key[keylen],"%%%02X",*c);
|
||||
keylen+=3;
|
||||
}
|
||||
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
if(!gotit)
|
||||
{
|
||||
fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err=http_post(key);
|
||||
if(err!=200)
|
||||
{
|
||||
fprintf(console,"gpgkeys: remote server returned error %d\n",err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret=0;
|
||||
|
||||
fail:
|
||||
|
||||
free(key);
|
||||
|
||||
if(ret!=0)
|
||||
fprintf(output,"KEY %s FAILED\n",keyid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_key(char *getkey)
|
||||
{
|
||||
int err,gotit=0;
|
||||
char search[29],line[MAX_LINE];
|
||||
|
||||
/* Build the search string. HKP only uses the short key IDs. */
|
||||
|
||||
if(strncmp(getkey,"0x",2)==0)
|
||||
getkey+=2;
|
||||
|
||||
if(strlen(getkey)==32)
|
||||
{
|
||||
fprintf(console,
|
||||
"gpgkeys: HKP keyservers do not support v3 fingerprints\n");
|
||||
fprintf(output,"KEY 0x%s BEGIN\n",getkey);
|
||||
fprintf(output,"KEY 0x%s FAILED\n",getkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strlen(getkey)>8)
|
||||
{
|
||||
char *offset=&getkey[strlen(getkey)-8];
|
||||
|
||||
/* fingerprint or long key id. Take the last 8 characters and
|
||||
treat it like a short key id */
|
||||
|
||||
sprintf(search,"0x%.8s",offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* short key id */
|
||||
|
||||
sprintf(search,"0x%.8s",getkey);
|
||||
}
|
||||
|
||||
fprintf(output,"KEY 0x%s BEGIN\n",getkey);
|
||||
|
||||
if(verbose>2)
|
||||
fprintf(console,"gpgkeys: HKP fetch for: %s\n",search);
|
||||
|
||||
fprintf(console,"gpgkeys: requesting key 0x%s from HKP keyserver %s\n",
|
||||
getkey,host);
|
||||
|
||||
err=http_get("get",search);
|
||||
if(err!=0)
|
||||
{
|
||||
fprintf(console,"gpgkeys: HKP fetch error: %s\n",strerror(errno));
|
||||
fprintf(output,"KEY 0x%s FAILED\n",getkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(fgets(line,MAX_LINE,server))
|
||||
{
|
||||
if(gotit)
|
||||
{
|
||||
fprintf(output,line);
|
||||
if(strcmp(line,"-----END PGP PUBLIC KEY BLOCK-----\n")==0)
|
||||
{
|
||||
gotit=0;
|
||||
fprintf(output,"KEY 0x%s END\n",getkey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if(strcmp(line,"-----BEGIN PGP PUBLIC KEY BLOCK-----\n")==0)
|
||||
{
|
||||
fprintf(output,line);
|
||||
gotit=1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_quoted(FILE *stream,char *string,char delim)
|
||||
{
|
||||
while(*string)
|
||||
{
|
||||
if(*string==delim)
|
||||
fprintf(stream,"\\x%02X",*string);
|
||||
else
|
||||
fputc(*string,stream);
|
||||
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
void append_quoted(char *buffer,char *string,char delim)
|
||||
{
|
||||
while(*buffer)
|
||||
buffer++;
|
||||
|
||||
while(*string)
|
||||
{
|
||||
if(*string==delim)
|
||||
{
|
||||
sprintf(buffer,"\\x%02X",*string);
|
||||
buffer+=4;
|
||||
}
|
||||
else
|
||||
*buffer=*string;
|
||||
|
||||
buffer++;
|
||||
string++;
|
||||
}
|
||||
|
||||
*buffer='\0';
|
||||
}
|
||||
|
||||
unsigned int scan_isodatestr( const char *string )
|
||||
{
|
||||
int year, month, day;
|
||||
struct tm tmbuf;
|
||||
time_t stamp;
|
||||
int i;
|
||||
|
||||
if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
|
||||
return 0;
|
||||
for( i=0; i < 4; i++ )
|
||||
if( !isdigit(string[i]) )
|
||||
return 0;
|
||||
if( !isdigit(string[5]) || !isdigit(string[6]) )
|
||||
return 0;
|
||||
if( !isdigit(string[8]) || !isdigit(string[9]) )
|
||||
return 0;
|
||||
year = atoi(string);
|
||||
month = atoi(string+5);
|
||||
day = atoi(string+8);
|
||||
/* some basic checks */
|
||||
if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
|
||||
return 0;
|
||||
memset( &tmbuf, 0, sizeof tmbuf );
|
||||
tmbuf.tm_mday = day;
|
||||
tmbuf.tm_mon = month-1;
|
||||
tmbuf.tm_year = year - 1900;
|
||||
tmbuf.tm_isdst = -1;
|
||||
stamp = mktime( &tmbuf );
|
||||
if( stamp == (time_t)-1 )
|
||||
return 0;
|
||||
return stamp;
|
||||
}
|
||||
|
||||
/* pub 2048/<a href="/pks/lookup?op=get&search=0x3CB3B415">3CB3B415</a> 1998/04/03 David M. Shaw <<a href="/pks/lookup?op=get&search=0x3CB3B415">dshaw@jabberwocky.com</a>> */
|
||||
|
||||
/* Luckily enough, both the HKP server and NAI HKP interface to their
|
||||
LDAP server are close enough in output so the same function can
|
||||
parse them both. */
|
||||
|
||||
int parse_hkp_index(char *line,char **buffer)
|
||||
{
|
||||
static int open=0,revoked=0;
|
||||
static char *key,*uid;
|
||||
static unsigned int bits,createtime;
|
||||
int ret=0;
|
||||
|
||||
/* printf("Open %d, LINE: %s\n",open,line); */
|
||||
|
||||
/* For multiple UIDs */
|
||||
if(open && uid!=NULL)
|
||||
{
|
||||
ret=0;
|
||||
|
||||
if(!(revoked && !include_revoked))
|
||||
{
|
||||
char intstr[11],*buf;
|
||||
|
||||
buf=realloc(*buffer,
|
||||
(*buffer?strlen(*buffer):0)+
|
||||
(strlen(key)*4)+
|
||||
1+
|
||||
(strlen(uid)*4)
|
||||
+1
|
||||
+2
|
||||
+10
|
||||
+4
|
||||
+10
|
||||
+1
|
||||
+1);
|
||||
|
||||
if(buf)
|
||||
*buffer=buf;
|
||||
else
|
||||
return -1;
|
||||
|
||||
append_quoted(*buffer,key,':');
|
||||
append_quoted(*buffer,":",0);
|
||||
append_quoted(*buffer,uid,':');
|
||||
append_quoted(*buffer,":",0);
|
||||
append_quoted(*buffer,revoked?"1:":":",0);
|
||||
sprintf(intstr,"%u",createtime);
|
||||
append_quoted(*buffer,intstr,':');
|
||||
append_quoted(*buffer,"::::",0);
|
||||
sprintf(intstr,"%u",bits);
|
||||
append_quoted(*buffer,intstr,':');
|
||||
append_quoted(*buffer,"\n",0);
|
||||
|
||||
ret=1;
|
||||
}
|
||||
|
||||
if(strncmp(line," ",5)!=0)
|
||||
{
|
||||
revoked=0;
|
||||
free(key);
|
||||
free(uid);
|
||||
uid=NULL;
|
||||
open=0;
|
||||
}
|
||||
}
|
||||
|
||||
if(strncasecmp(line,"pub ",5)==0)
|
||||
{
|
||||
char *tok,*temp;
|
||||
|
||||
open=1;
|
||||
|
||||
line+=4;
|
||||
|
||||
tok=strsep(&line,"/");
|
||||
if(tok==NULL)
|
||||
return ret;
|
||||
|
||||
bits=atoi(tok);
|
||||
|
||||
tok=strsep(&line,">");
|
||||
if(tok==NULL)
|
||||
return ret;
|
||||
|
||||
tok=strsep(&line,"<");
|
||||
if(tok==NULL)
|
||||
{
|
||||
key=strdup("00000000");
|
||||
return ret;
|
||||
}
|
||||
|
||||
key=strdup(tok);
|
||||
|
||||
tok=strsep(&line," ");
|
||||
if(tok==NULL)
|
||||
return ret;
|
||||
|
||||
tok=strsep(&line," ");
|
||||
if(tok==NULL)
|
||||
return ret;
|
||||
|
||||
/* The date parser wants '-' instead of '/', so... */
|
||||
temp=tok;
|
||||
while(*temp!='\0')
|
||||
{
|
||||
if(*temp=='/')
|
||||
*temp='-';
|
||||
|
||||
temp++;
|
||||
}
|
||||
|
||||
createtime=scan_isodatestr(tok);
|
||||
}
|
||||
|
||||
if(open)
|
||||
{
|
||||
int uidindex=0;
|
||||
|
||||
if(line==NULL)
|
||||
{
|
||||
uid=strdup("Key index corrupted");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* All that's left is the user name. Strip off anything
|
||||
<between brackets> and de-urlencode it. */
|
||||
|
||||
while(*line==' ' && *line!='\0')
|
||||
line++;
|
||||
|
||||
if(strncmp(line,"*** KEY REVOKED ***",19)==0)
|
||||
{
|
||||
revoked=1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uid=malloc(strlen(line)+1);
|
||||
|
||||
while(*line!='\0')
|
||||
{
|
||||
switch(*line)
|
||||
{
|
||||
case '<':
|
||||
while(*line!='>' && *line!='\0')
|
||||
line++;
|
||||
|
||||
if(*line!='\0')
|
||||
line++;
|
||||
break;
|
||||
|
||||
case '&':
|
||||
if((*(line+1)!='\0' && tolower(*(line+1))=='l') &&
|
||||
(*(line+2)!='\0' && tolower(*(line+2))=='t') &&
|
||||
(*(line+3)!='\0' && *(line+3)==';'))
|
||||
{
|
||||
uid[uidindex++]='<';
|
||||
line+=4;
|
||||
break;
|
||||
}
|
||||
|
||||
if((*(line+1)!='\0' && tolower(*(line+1))=='g') &&
|
||||
(*(line+2)!='\0' && tolower(*(line+2))=='t') &&
|
||||
(*(line+3)!='\0' && *(line+3)==';'))
|
||||
{
|
||||
uid[uidindex++]='>';
|
||||
line+=4;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
uid[uidindex++]=*line;
|
||||
line++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uid[uidindex]='\0';
|
||||
|
||||
/* Chop off the trailing \r, \n, or both. This is fussy as the
|
||||
true HKP servers have \r\n, and the NAI HKP servers have just
|
||||
\n. */
|
||||
|
||||
if(isspace(uid[uidindex-1]))
|
||||
uid[uidindex-1]='\0';
|
||||
|
||||
if(isspace(uid[uidindex-2]))
|
||||
uid[uidindex-2]='\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int search_key(char *searchkey)
|
||||
{
|
||||
int ret=-1,err,count=0;
|
||||
char *search,*request,*buffer=NULL;
|
||||
char line[1024];
|
||||
int max,len;
|
||||
|
||||
fprintf(output,"SEARCH %s BEGIN\n",searchkey);
|
||||
|
||||
/* Build the search string. It's going to need url-encoding. */
|
||||
|
||||
max=0;
|
||||
len=0;
|
||||
search=NULL;
|
||||
request=searchkey;
|
||||
|
||||
while(*request!='\0')
|
||||
{
|
||||
if(max-len<3)
|
||||
{
|
||||
max+=100;
|
||||
search=realloc(search,max+1); /* Note +1 for \0 */
|
||||
}
|
||||
|
||||
if(isalnum(*request) || *request=='-')
|
||||
search[len++]=*request;
|
||||
else if(*request==' ')
|
||||
search[len++]='+';
|
||||
else
|
||||
{
|
||||
sprintf(&search[len],"%%%02X",*request);
|
||||
len+=3;
|
||||
}
|
||||
|
||||
request++;
|
||||
}
|
||||
|
||||
search[len]='\0';
|
||||
|
||||
if(verbose>2)
|
||||
fprintf(console,"gpgkeys: HKP search for: %s\n",search);
|
||||
|
||||
fprintf(console,("gpgkeys: searching for \"%s\" from HKP server %s\n"),
|
||||
searchkey,host);
|
||||
|
||||
http_get("index",search);
|
||||
|
||||
free(search);
|
||||
|
||||
while(fgets(line,1024,server))
|
||||
{
|
||||
err=parse_hkp_index(line,&buffer);
|
||||
if(err==-1)
|
||||
goto fail;
|
||||
|
||||
count+=err;
|
||||
}
|
||||
|
||||
fprintf(output,"COUNT %d\n%s",count,buffer);
|
||||
// fprintf(output,"COUNT -1\n%s",buffer);
|
||||
|
||||
fprintf(output,"SEARCH %s END\n",searchkey);
|
||||
|
||||
ret=0;
|
||||
|
||||
fail:
|
||||
free(buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int port=0,arg,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
|
||||
char line[MAX_LINE];
|
||||
int version,failed=0;
|
||||
struct keylist *keylist=NULL,*keyptr=NULL;
|
||||
|
||||
console=stderr;
|
||||
|
||||
fprintf(console,
|
||||
"gpgkeys: Warning: this is an *experimental* HKP interface!\n");
|
||||
|
||||
while((arg=getopt(argc,argv,"ho:"))!=-1)
|
||||
switch(arg)
|
||||
{
|
||||
default:
|
||||
case 'h':
|
||||
fprintf(console,"-h\thelp\n");
|
||||
fprintf(console,"-o\toutput to this file\n");
|
||||
return KEYSERVER_OK;
|
||||
|
||||
case 'o':
|
||||
output=fopen(optarg,"w");
|
||||
if(output==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: Cannot open output file \"%s\": %s\n",
|
||||
optarg,strerror(errno));
|
||||
return KEYSERVER_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(argc>optind)
|
||||
{
|
||||
input=fopen(argv[optind],"r");
|
||||
if(input==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: Cannot open input file \"%s\": %s\n",
|
||||
argv[optind],strerror(errno));
|
||||
return KEYSERVER_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if(input==NULL)
|
||||
input=stdin;
|
||||
|
||||
if(output==NULL)
|
||||
output=stdout;
|
||||
|
||||
/* Get the command and info block */
|
||||
|
||||
while(fgets(line,MAX_LINE,input)!=NULL)
|
||||
{
|
||||
char commandstr[7];
|
||||
char portstr[10];
|
||||
char optionstr[30];
|
||||
char hash;
|
||||
|
||||
if(line[0]=='\n')
|
||||
break;
|
||||
|
||||
if(sscanf(line,"%c",&hash)==1 && hash=='#')
|
||||
continue;
|
||||
|
||||
if(sscanf(line,"COMMAND %6s\n",commandstr)==1)
|
||||
{
|
||||
commandstr[6]='\0';
|
||||
|
||||
if(strcasecmp(commandstr,"get")==0)
|
||||
action=GET;
|
||||
else if(strcasecmp(commandstr,"send")==0)
|
||||
action=SEND;
|
||||
else if(strcasecmp(commandstr,"search")==0)
|
||||
action=SEARCH;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(sscanf(line,"HOST %79s\n",host)==1)
|
||||
{
|
||||
host[79]='\0';
|
||||
continue;
|
||||
}
|
||||
|
||||
if(sscanf(line,"PORT %9s\n",portstr)==1)
|
||||
{
|
||||
portstr[9]='\0';
|
||||
port=atoi(portstr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(sscanf(line,"VERSION %d\n",&version)==1)
|
||||
{
|
||||
if(version!=0)
|
||||
{
|
||||
ret=KEYSERVER_VERSION_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(sscanf(line,"OPTION %29s\n",optionstr)==1)
|
||||
{
|
||||
int no=0;
|
||||
char *start=&optionstr[0];
|
||||
|
||||
optionstr[29]='\0';
|
||||
|
||||
if(strncasecmp(optionstr,"no-",3)==0)
|
||||
{
|
||||
no=1;
|
||||
start=&optionstr[3];
|
||||
}
|
||||
|
||||
if(strcasecmp(start,"verbose")==0)
|
||||
{
|
||||
if(no)
|
||||
verbose--;
|
||||
else
|
||||
verbose++;
|
||||
}
|
||||
else if(strcasecmp(start,"include-disabled")==0)
|
||||
{
|
||||
if(no)
|
||||
include_disabled=0;
|
||||
else
|
||||
include_disabled=1;
|
||||
}
|
||||
else if(strcasecmp(start,"include-revoked")==0)
|
||||
{
|
||||
if(no)
|
||||
include_revoked=0;
|
||||
else
|
||||
include_revoked=1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's a GET or a SEARCH, the next thing to come in is the
|
||||
keyids. If it's a SEND, then there are no keyids. */
|
||||
|
||||
if(action==SEND)
|
||||
while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
|
||||
else if(action==GET || action==SEARCH)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
struct keylist *work;
|
||||
|
||||
if(fgets(line,MAX_LINE,input)==NULL)
|
||||
break;
|
||||
else
|
||||
{
|
||||
if(line[0]=='\n')
|
||||
break;
|
||||
|
||||
work=malloc(sizeof(struct keylist));
|
||||
if(work==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: out of memory while "
|
||||
"building key list\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
strcpy(work->str,line);
|
||||
|
||||
/* Trim the trailing \n */
|
||||
work->str[strlen(line)-1]='\0';
|
||||
|
||||
work->next=NULL;
|
||||
|
||||
/* Always attach at the end to keep the list in proper
|
||||
order for searching */
|
||||
if(keylist==NULL)
|
||||
keylist=work;
|
||||
else
|
||||
keyptr->next=work;
|
||||
|
||||
keyptr=work;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(console,"gpgkeys: no keyserver command specified\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Send the response */
|
||||
|
||||
fprintf(output,"VERSION 0\n");
|
||||
fprintf(output,"PROGRAM %s\n\n",VERSION);
|
||||
|
||||
if(verbose>1)
|
||||
{
|
||||
fprintf(console,"Host:\t\t%s\n",host);
|
||||
if(port)
|
||||
fprintf(console,"Port:\t\t%d\n",port);
|
||||
fprintf(console,"Command:\t%s\n",action==GET?"GET":
|
||||
action==SEND?"SEND":"SEARCH");
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(verbose>1)
|
||||
{
|
||||
vals=ldap_get_values(ldap,res,"software");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(console,"Server: \t%s\n",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,res,"version");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(console,"Version:\t%s\n",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case GET:
|
||||
keyptr=keylist;
|
||||
|
||||
while(keyptr!=NULL)
|
||||
{
|
||||
http_connect(host,port);
|
||||
|
||||
if(get_key(keyptr->str)==-1)
|
||||
failed++;
|
||||
|
||||
http_disconnect();
|
||||
|
||||
keyptr=keyptr->next;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEND:
|
||||
{
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
http_connect(host,port);
|
||||
ret=send_key();
|
||||
if(ret==-1)
|
||||
failed++;
|
||||
http_disconnect();
|
||||
}
|
||||
while(ret!=1);
|
||||
}
|
||||
break;
|
||||
|
||||
case SEARCH:
|
||||
{
|
||||
char *searchkey=NULL;
|
||||
int len=0;
|
||||
|
||||
/* To search, we stick a space in between each key to search
|
||||
for. */
|
||||
|
||||
keyptr=keylist;
|
||||
while(keyptr!=NULL)
|
||||
{
|
||||
len+=strlen(keyptr->str)+1;
|
||||
keyptr=keyptr->next;
|
||||
}
|
||||
|
||||
searchkey=malloc(len+1);
|
||||
if(searchkey==NULL)
|
||||
goto fail;
|
||||
|
||||
searchkey[0]='\0';
|
||||
|
||||
keyptr=keylist;
|
||||
while(keyptr!=NULL)
|
||||
{
|
||||
strcat(searchkey,keyptr->str);
|
||||
strcat(searchkey," ");
|
||||
keyptr=keyptr->next;
|
||||
}
|
||||
|
||||
/* Nail that last space */
|
||||
searchkey[strlen(searchkey)-1]='\0';
|
||||
|
||||
http_connect(host,port);
|
||||
|
||||
if(search_key(searchkey)==-1)
|
||||
{
|
||||
fprintf(output,"SEARCH %s FAILED\n",searchkey);
|
||||
failed++;
|
||||
}
|
||||
|
||||
http_disconnect();
|
||||
|
||||
free(searchkey);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(!failed)
|
||||
ret=KEYSERVER_OK;
|
||||
|
||||
fail:
|
||||
|
||||
while(keylist!=NULL)
|
||||
{
|
||||
struct keylist *current=keylist;
|
||||
keylist=keylist->next;
|
||||
free(current);
|
||||
}
|
||||
|
||||
if(input!=stdin)
|
||||
fclose(input);
|
||||
|
||||
if(output!=stdout)
|
||||
fclose(output);
|
||||
|
||||
return ret;
|
||||
}
|
986
keyserver/gpgkeys_ldap.c
Normal file
986
keyserver/gpgkeys_ldap.c
Normal file
|
@ -0,0 +1,986 @@
|
|||
/* gpgkeys_ldap.c - talk to a LDAP keyserver
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#ifdef NEED_LBER_H
|
||||
#include <lber.h>
|
||||
#endif
|
||||
#include <ldap.h>
|
||||
#include "keyserver.h"
|
||||
|
||||
#ifdef __riscos__
|
||||
#include <unixlib/local.h>
|
||||
#endif
|
||||
|
||||
#define GET 0
|
||||
#define SEND 1
|
||||
#define SEARCH 2
|
||||
#define MAX_LINE 80
|
||||
|
||||
int verbose=0,include_disabled=0,include_revoked=0,include_subkeys=0;
|
||||
char *basekeyspacedn=NULL;
|
||||
char host[80];
|
||||
FILE *input=NULL,*output=NULL,*console=NULL;
|
||||
LDAP *ldap=NULL;
|
||||
|
||||
struct keylist
|
||||
{
|
||||
char str[MAX_LINE];
|
||||
struct keylist *next;
|
||||
};
|
||||
|
||||
/* Returns 0 on success, -1 on failure, and 1 on eof */
|
||||
int send_key(void)
|
||||
{
|
||||
int err,gotit=0,keysize=1,ret=-1;
|
||||
char *dn=NULL;
|
||||
char line[MAX_LINE];
|
||||
char *key[2]={0,0};
|
||||
char keyid[17];
|
||||
#ifndef __riscos__
|
||||
LDAPMod mod={LDAP_MOD_ADD,"pgpKeyV2",{key}},*attrs[2]={&mod,NULL};
|
||||
#else
|
||||
LDAPMod mod, *attrs[2];
|
||||
|
||||
mod.mod_op = LDAP_MOD_ADD;
|
||||
mod.mod_type = "pgpKeyV2";
|
||||
mod.mod_values = 0;
|
||||
mod.mod_bvalues = 0;
|
||||
|
||||
attrs[0] = &mod;
|
||||
attrs[1] = NULL;
|
||||
#endif
|
||||
|
||||
dn=malloc(strlen("pgpCertid=virtual,")+strlen(basekeyspacedn)+1);
|
||||
if(dn==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: can't allocate memory for keyserver record\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
strcpy(dn,"pgpCertid=virtual,");
|
||||
strcat(dn,basekeyspacedn);
|
||||
|
||||
key[0]=malloc(1);
|
||||
if(key[0]==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: unable to allocate memory for key\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
key[0][0]='\0';
|
||||
|
||||
/* Read and throw away stdin until we see the BEGIN */
|
||||
|
||||
while(fgets(line,MAX_LINE,input)!=NULL)
|
||||
if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1)
|
||||
{
|
||||
gotit=1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!gotit)
|
||||
{
|
||||
/* i.e. eof before the KEY BEGIN was found */
|
||||
ret=1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
gotit=0;
|
||||
|
||||
/* Now slurp up everything until we see the END */
|
||||
|
||||
while(fgets(line,MAX_LINE,input)!=NULL)
|
||||
if(sscanf(line,"KEY %16s END\n",keyid)==1)
|
||||
{
|
||||
gotit=1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
keysize+=strlen(line);
|
||||
key[0]=realloc(key[0],keysize);
|
||||
if(key[0]==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: unable to reallocate for key\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
strcat(key[0],line);
|
||||
}
|
||||
|
||||
if(!gotit)
|
||||
{
|
||||
fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err=ldap_add_s(ldap,dn,attrs);
|
||||
if(err!=LDAP_SUCCESS)
|
||||
{
|
||||
fprintf(console,"gpgkeys: error adding key %s to keyserver: %s\n",
|
||||
keyid,ldap_err2string(err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret=0;
|
||||
|
||||
fail:
|
||||
|
||||
free(key[0]);
|
||||
free(dn);
|
||||
|
||||
if(ret!=0)
|
||||
fprintf(output,"KEY %s FAILED\n",keyid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns 0 on success and -1 on failure. Note that key-not-found is
|
||||
not an error! */
|
||||
int get_key(char *getkey)
|
||||
{
|
||||
char **vals;
|
||||
LDAPMessage *res,*each;
|
||||
int ret=-1,err,count;
|
||||
struct keylist *dupelist=NULL;
|
||||
char search[62];
|
||||
char *attrs[]={"pgpKeyV2","pgpuserid","pgpkeyid","pgpcertid","pgprevoked",
|
||||
"pgpdisabled","pgpkeycreatetime","modifytimestamp",
|
||||
"pgpkeysize","pgpkeytype",NULL};
|
||||
|
||||
/* Build the search string */
|
||||
|
||||
/* GPG can send us a v4 fingerprint, a v3 or v4 long key id, or a v3
|
||||
or v4 short key id */
|
||||
|
||||
if(strncmp(getkey,"0x",2)==0)
|
||||
getkey+=2;
|
||||
|
||||
if(strlen(getkey)==32)
|
||||
{
|
||||
fprintf(console,
|
||||
"gpgkeys: LDAP keyservers do not support v3 fingerprints\n");
|
||||
fprintf(output,"KEY 0x%s BEGIN\n",getkey);
|
||||
fprintf(output,"KEY 0x%s FAILED\n",getkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strlen(getkey)>16)
|
||||
{
|
||||
char *offset=&getkey[strlen(getkey)-16];
|
||||
|
||||
/* fingerprint. Take the last 16 characters and treat it like a
|
||||
long key id */
|
||||
|
||||
if(include_subkeys)
|
||||
sprintf(search,"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))",
|
||||
offset,offset);
|
||||
else
|
||||
sprintf(search,"(pgpcertid=%.16s)",offset);
|
||||
}
|
||||
else if(strlen(getkey)>8)
|
||||
{
|
||||
/* long key id */
|
||||
|
||||
if(include_subkeys)
|
||||
sprintf(search,"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))",
|
||||
getkey,getkey);
|
||||
else
|
||||
sprintf(search,"(pgpcertid=%.16s)",getkey);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* short key id */
|
||||
|
||||
sprintf(search,"(pgpkeyid=%.8s)",getkey);
|
||||
}
|
||||
|
||||
fprintf(output,"KEY 0x%s BEGIN\n",getkey);
|
||||
|
||||
if(verbose>2)
|
||||
fprintf(console,"gpgkeys: LDAP fetch for: %s\n",search);
|
||||
|
||||
if(!verbose)
|
||||
attrs[1]=NULL;
|
||||
|
||||
fprintf(console,"gpgkeys: requesting key 0x%s from LDAP keyserver %s\n",
|
||||
getkey,host);
|
||||
|
||||
err=ldap_search_s(ldap,basekeyspacedn,
|
||||
LDAP_SCOPE_SUBTREE,search,attrs,0,&res);
|
||||
if(err!=0)
|
||||
{
|
||||
fprintf(console,"gpgkeys: LDAP search error: %s\n",ldap_err2string(err));
|
||||
fprintf(output,"KEY 0x%s FAILED\n",getkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
count=ldap_count_entries(ldap,res);
|
||||
if(count<1)
|
||||
{
|
||||
fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
|
||||
fprintf(output,"KEY 0x%s FAILED\n",getkey);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There may be more than one unique result for a given keyID,
|
||||
so we should fetch them all (test this by fetching short key
|
||||
id 0xDEADBEEF). */
|
||||
|
||||
each=ldap_first_entry(ldap,res);
|
||||
while(each!=NULL)
|
||||
{
|
||||
struct keylist *keyptr=dupelist;
|
||||
|
||||
/* Use the long keyid to remove duplicates. The LDAP server
|
||||
returns the same keyid more than once if there are
|
||||
multiple user IDs on the key. Note that this does NOT
|
||||
mean that a keyid that exists multiple times on the
|
||||
keyserver will not be fetched. It means that each KEY,
|
||||
no matter how many user IDs share it's keyid, will be
|
||||
fetched only once. If a keyid that belongs to more than
|
||||
one key is fetched, the server quite properly responds
|
||||
with all matching keys. -ds */
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpcertid");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
while(keyptr!=NULL)
|
||||
{
|
||||
if(strcasecmp(keyptr->str,vals[0])==0)
|
||||
break;
|
||||
|
||||
keyptr=keyptr->next;
|
||||
}
|
||||
|
||||
if(!keyptr)
|
||||
{
|
||||
/* it's not a duplicate, so add it */
|
||||
|
||||
keyptr=malloc(sizeof(struct keylist));
|
||||
if(keyptr==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: out of memory when deduping "
|
||||
"key list\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
strncpy(keyptr->str,vals[0],MAX_LINE);
|
||||
keyptr->str[MAX_LINE-1]='\0';
|
||||
|
||||
keyptr->next=dupelist;
|
||||
dupelist=keyptr;
|
||||
keyptr=NULL;
|
||||
}
|
||||
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
if(!keyptr) /* it's not a duplicate */
|
||||
{
|
||||
if(verbose)
|
||||
{
|
||||
vals=ldap_get_values(ldap,each,"pgpuserid");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
/* This is wrong, as the user ID is UTF8. A
|
||||
better way to handle this would be to send it
|
||||
over to gpg and display it on that side of
|
||||
the pipe. */
|
||||
fprintf(console,"\nUser ID:\t%s\n",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgprevoked");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
if(atoi(vals[0])==1)
|
||||
fprintf(console,"\t\t** KEY REVOKED **\n");
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpdisabled");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
if(atoi(vals[0])==1)
|
||||
fprintf(console,"\t\t** KEY DISABLED **\n");
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpkeyid");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(console,"Short key ID:\t%s\n",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpcertid");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(console,"Long key ID:\t%s\n",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
/* YYYYMMDDHHmmssZ */
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpkeycreatetime");
|
||||
if(vals!=NULL && strlen(vals[0])==15)
|
||||
{
|
||||
fprintf(console,"Key created:\t%.2s/%.2s/%.4s\n",
|
||||
&vals[0][4],&vals[0][6],vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,each,"modifytimestamp");
|
||||
if(vals!=NULL && strlen(vals[0])==15)
|
||||
{
|
||||
fprintf(console,"Key modified:\t%.2s/%.2s/%.4s\n",
|
||||
&vals[0][4],&vals[0][6],vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpkeysize");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(console,"Key size:\t%d\n",atoi(vals[0]));
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpkeytype");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(console,"Key type:\t%s\n",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpKeyV2");
|
||||
if(vals==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: unable to retrieve key %s "
|
||||
"from keyserver\n",getkey);
|
||||
fprintf(output,"KEY 0x%s FAILED\n",getkey);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(output,"%sKEY 0x%s END\n",vals[0],getkey);
|
||||
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
}
|
||||
|
||||
each=ldap_next_entry(ldap,each);
|
||||
}
|
||||
}
|
||||
|
||||
ret=0;
|
||||
|
||||
fail:
|
||||
ldap_msgfree(res);
|
||||
|
||||
/* free up the dupe checker */
|
||||
while(dupelist!=NULL)
|
||||
{
|
||||
struct keylist *keyptr=dupelist;
|
||||
|
||||
dupelist=keyptr->next;
|
||||
free(keyptr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
time_t ldap2epochtime(const char *timestr)
|
||||
{
|
||||
struct tm pgptime;
|
||||
|
||||
memset(&pgptime,0,sizeof(pgptime));
|
||||
|
||||
/* YYYYMMDDHHmmssZ */
|
||||
|
||||
sscanf(timestr,"%4d%2d%2d%2d%2d%2d",
|
||||
&pgptime.tm_year,
|
||||
&pgptime.tm_mon,
|
||||
&pgptime.tm_mday,
|
||||
&pgptime.tm_hour,
|
||||
&pgptime.tm_min,
|
||||
&pgptime.tm_sec);
|
||||
|
||||
pgptime.tm_year-=1900;
|
||||
pgptime.tm_isdst=-1;
|
||||
pgptime.tm_mon--;
|
||||
|
||||
return mktime(&pgptime);
|
||||
}
|
||||
|
||||
void printquoted(FILE *stream,char *string,char delim)
|
||||
{
|
||||
while(*string)
|
||||
{
|
||||
if(*string==delim || *string=='\\')
|
||||
fprintf(stream,"\\x%02x",*string);
|
||||
else
|
||||
fputc(*string,stream);
|
||||
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns 0 on success and -1 on error. Note that key-not-found is
|
||||
not an error! */
|
||||
int search_key(char *searchkey)
|
||||
{
|
||||
char **vals;
|
||||
LDAPMessage *res,*each;
|
||||
int err,count;
|
||||
/* The maxium size of the search, including the optional stuff and
|
||||
the trailing \0 */
|
||||
char search[2+12+MAX_LINE+2+15+14+1+1];
|
||||
char *attrs[]={"pgpcertid","pgpuserid","pgprevoked","pgpdisabled",
|
||||
"pgpkeycreatetime","pgpkeyexpiretime","modifytimestamp",
|
||||
"pgpkeysize","pgpkeytype",NULL};
|
||||
|
||||
fprintf(output,"SEARCH %s BEGIN\n",searchkey);
|
||||
|
||||
/* Build the search string */
|
||||
|
||||
sprintf(search,"%s(pgpuserid=*%s*)%s%s%s",
|
||||
(!(include_disabled&&include_revoked))?"(&":"",
|
||||
searchkey,
|
||||
include_disabled?"":"(pgpdisabled=0)",
|
||||
include_revoked?"":"(pgprevoked=0)",
|
||||
!(include_disabled&&include_revoked)?")":"");
|
||||
|
||||
if(verbose>2)
|
||||
fprintf(console,"gpgkeys: LDAP search for: %s\n",search);
|
||||
|
||||
fprintf(console,("gpgkeys: searching for \"%s\" from LDAP server %s\n"),
|
||||
searchkey,host);
|
||||
|
||||
err=ldap_search_s(ldap,basekeyspacedn,
|
||||
LDAP_SCOPE_SUBTREE,search,attrs,0,&res);
|
||||
if(err!=0)
|
||||
{
|
||||
fprintf(console,"gpgkeys: LDAP search error: %s\n",ldap_err2string(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
count=ldap_count_entries(ldap,res);
|
||||
|
||||
if(count<1)
|
||||
fprintf(output,"COUNT 0\n");
|
||||
else
|
||||
{
|
||||
fprintf(output,"COUNT %d\n",count);
|
||||
|
||||
each=ldap_first_entry(ldap,res);
|
||||
while(each!=NULL)
|
||||
{
|
||||
int flags=0;
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpcertid");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(output,"%s:",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
else
|
||||
fputc(':',output);
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpuserid");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
/* Need to escape any colons */
|
||||
printquoted(output,vals[0],':');
|
||||
fputc(':',output);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
else
|
||||
fputc(':',output);
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgprevoked");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
if(atoi(vals[0])==1)
|
||||
flags|=1;
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpdisabled");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
if(atoi(vals[0])==1)
|
||||
flags|=2;
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
fprintf(output,"%d:",flags);
|
||||
|
||||
/* YYYYMMDDHHmmssZ */
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpkeycreatetime");
|
||||
if(vals!=NULL && strlen(vals[0])==15)
|
||||
{
|
||||
fprintf(output,"%u:",(unsigned int)ldap2epochtime(vals[0]));
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
else
|
||||
fputc(':',output);
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpkeyexpiretime");
|
||||
if(vals!=NULL && strlen(vals[0])==15)
|
||||
{
|
||||
fprintf(output,"%u:",(unsigned int)ldap2epochtime(vals[0]));
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
else
|
||||
fputc(':',output);
|
||||
|
||||
vals=ldap_get_values(ldap,each,"modifytimestamp");
|
||||
if(vals!=NULL && strlen(vals[0])==15)
|
||||
{
|
||||
fprintf(output,"%u:",(unsigned int)ldap2epochtime(vals[0]));
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
else
|
||||
fputc(':',output);
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpkeytype");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(output,"%s:",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
else
|
||||
fputc(':',output);
|
||||
|
||||
vals=ldap_get_values(ldap,each,"pgpkeysize");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
/* Not sure why, but some keys are listed with a key size of
|
||||
0. Treat that like an unknown. */
|
||||
if(atoi(vals[0])>0)
|
||||
fprintf(output,"%d",atoi(vals[0]));
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
fputc('\n',output);
|
||||
|
||||
each=ldap_next_entry(ldap,each);
|
||||
}
|
||||
}
|
||||
|
||||
ldap_msgfree(res);
|
||||
|
||||
fprintf(output,"SEARCH %s END\n",searchkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int port=0,arg,err,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
|
||||
char line[MAX_LINE],**vals;
|
||||
int version,failed=0;
|
||||
char *attrs[]={"basekeyspacedn","version","software",NULL};
|
||||
LDAPMessage *res;
|
||||
struct keylist *keylist=NULL,*keyptr=NULL;
|
||||
|
||||
#ifdef __riscos__
|
||||
__riscosify_control = __RISCOSIFY_NO_PROCESS;
|
||||
#endif
|
||||
|
||||
console=stderr;
|
||||
|
||||
while((arg=getopt(argc,argv,"ho:"))!=-1)
|
||||
switch(arg)
|
||||
{
|
||||
default:
|
||||
case 'h':
|
||||
fprintf(console,"-h\thelp\n");
|
||||
fprintf(console,"-o\toutput to this file\n");
|
||||
return KEYSERVER_OK;
|
||||
|
||||
case 'o':
|
||||
output=fopen(optarg,"w");
|
||||
if(output==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: Cannot open output file \"%s\": %s\n",
|
||||
optarg,strerror(errno));
|
||||
return KEYSERVER_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(argc>optind)
|
||||
{
|
||||
input=fopen(argv[optind],"r");
|
||||
if(input==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: Cannot open input file \"%s\": %s\n",
|
||||
argv[optind],strerror(errno));
|
||||
return KEYSERVER_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if(input==NULL)
|
||||
input=stdin;
|
||||
|
||||
if(output==NULL)
|
||||
output=stdout;
|
||||
|
||||
/* Get the command and info block */
|
||||
|
||||
while(fgets(line,MAX_LINE,input)!=NULL)
|
||||
{
|
||||
char commandstr[7];
|
||||
char portstr[10];
|
||||
char optionstr[30];
|
||||
char hash;
|
||||
|
||||
if(line[0]=='\n')
|
||||
break;
|
||||
|
||||
if(sscanf(line,"%c",&hash)==1 && hash=='#')
|
||||
continue;
|
||||
|
||||
if(sscanf(line,"COMMAND %6s\n",commandstr)==1)
|
||||
{
|
||||
commandstr[6]='\0';
|
||||
|
||||
if(strcasecmp(commandstr,"get")==0)
|
||||
action=GET;
|
||||
else if(strcasecmp(commandstr,"send")==0)
|
||||
action=SEND;
|
||||
else if(strcasecmp(commandstr,"search")==0)
|
||||
action=SEARCH;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(sscanf(line,"HOST %79s\n",host)==1)
|
||||
{
|
||||
host[79]='\0';
|
||||
continue;
|
||||
}
|
||||
|
||||
if(sscanf(line,"PORT %9s\n",portstr)==1)
|
||||
{
|
||||
portstr[9]='\0';
|
||||
port=atoi(portstr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(sscanf(line,"VERSION %d\n",&version)==1)
|
||||
{
|
||||
if(version!=0)
|
||||
{
|
||||
ret=KEYSERVER_VERSION_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(sscanf(line,"OPTION %29s\n",optionstr)==1)
|
||||
{
|
||||
int no=0;
|
||||
char *start=&optionstr[0];
|
||||
|
||||
optionstr[29]='\0';
|
||||
|
||||
if(strncasecmp(optionstr,"no-",3)==0)
|
||||
{
|
||||
no=1;
|
||||
start=&optionstr[3];
|
||||
}
|
||||
|
||||
if(strcasecmp(start,"verbose")==0)
|
||||
{
|
||||
if(no)
|
||||
verbose--;
|
||||
else
|
||||
verbose++;
|
||||
}
|
||||
else if(strcasecmp(start,"include-disabled")==0)
|
||||
{
|
||||
if(no)
|
||||
include_disabled=0;
|
||||
else
|
||||
include_disabled=1;
|
||||
}
|
||||
else if(strcasecmp(start,"include-revoked")==0)
|
||||
{
|
||||
if(no)
|
||||
include_revoked=0;
|
||||
else
|
||||
include_revoked=1;
|
||||
}
|
||||
else if(strcasecmp(start,"include-subkeys")==0)
|
||||
{
|
||||
if(no)
|
||||
include_subkeys=0;
|
||||
else
|
||||
include_subkeys=1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's a GET or a SEARCH, the next thing to come in is the
|
||||
keyids. If it's a SEND, then there are no keyids. */
|
||||
|
||||
if(action==SEND)
|
||||
while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
|
||||
else if(action==GET || action==SEARCH)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
struct keylist *work;
|
||||
|
||||
if(fgets(line,MAX_LINE,input)==NULL)
|
||||
break;
|
||||
else
|
||||
{
|
||||
if(line[0]=='\n')
|
||||
break;
|
||||
|
||||
work=malloc(sizeof(struct keylist));
|
||||
if(work==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: out of memory while "
|
||||
"building key list\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
strcpy(work->str,line);
|
||||
|
||||
/* Trim the trailing \n */
|
||||
work->str[strlen(line)-1]='\0';
|
||||
|
||||
work->next=NULL;
|
||||
|
||||
/* Always attach at the end to keep the list in proper
|
||||
order for searching */
|
||||
if(keylist==NULL)
|
||||
keylist=work;
|
||||
else
|
||||
keyptr->next=work;
|
||||
|
||||
keyptr=work;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(console,"gpgkeys: no keyserver command specified\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Send the response */
|
||||
|
||||
fprintf(output,"VERSION 0\n");
|
||||
fprintf(output,"PROGRAM %s\n\n",VERSION);
|
||||
|
||||
if(verbose>1)
|
||||
{
|
||||
fprintf(console,"Host:\t\t%s\n",host);
|
||||
if(port)
|
||||
fprintf(console,"Port:\t\t%d\n",port);
|
||||
fprintf(console,"Command:\t%s\n",action==GET?"GET":
|
||||
action==SEND?"SEND":"SEARCH");
|
||||
}
|
||||
|
||||
ldap=ldap_init(host,port);
|
||||
if(ldap==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: internal LDAP init error: %s\n",strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err=ldap_simple_bind_s(ldap,NULL,NULL);
|
||||
if(err!=0)
|
||||
{
|
||||
fprintf(console,"gpgkeys: internal LDAP bind error: %s\n",
|
||||
ldap_err2string(err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Get the magic info record */
|
||||
|
||||
err=ldap_search_s(ldap,"cn=PGPServerInfo",LDAP_SCOPE_BASE,
|
||||
"(objectclass=*)",attrs,0,&res);
|
||||
if(err==-1)
|
||||
{
|
||||
fprintf(console,"gpgkeys: error retrieving LDAP server info: %s\n",
|
||||
ldap_err2string(err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(ldap_count_entries(ldap,res)!=1)
|
||||
{
|
||||
fprintf(console,"gpgkeys: more than one serverinfo record\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(verbose>1)
|
||||
{
|
||||
vals=ldap_get_values(ldap,res,"software");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(console,"Server: \t%s\n",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
vals=ldap_get_values(ldap,res,"version");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
fprintf(console,"Version:\t%s\n",vals[0]);
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is always "OU=ACTIVE,O=PGP KEYSPACE,C=US", but it might not
|
||||
be in the future. */
|
||||
|
||||
vals=ldap_get_values(ldap,res,"basekeyspacedn");
|
||||
if(vals!=NULL)
|
||||
{
|
||||
basekeyspacedn=strdup(vals[0]);
|
||||
if(basekeyspacedn==NULL)
|
||||
{
|
||||
fprintf(console,"gpgkeys: can't allocate string space "
|
||||
"for LDAP base\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ldap_value_free(vals);
|
||||
}
|
||||
|
||||
ldap_msgfree(res);
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case GET:
|
||||
keyptr=keylist;
|
||||
|
||||
while(keyptr!=NULL)
|
||||
{
|
||||
if(get_key(keyptr->str)==-1)
|
||||
failed++;
|
||||
|
||||
keyptr=keyptr->next;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEND:
|
||||
{
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
ret=send_key();
|
||||
if(ret==-1)
|
||||
failed++;
|
||||
}
|
||||
while(ret!=1);
|
||||
}
|
||||
break;
|
||||
|
||||
case SEARCH:
|
||||
{
|
||||
char *searchkey=NULL;
|
||||
int len=0;
|
||||
|
||||
/* To search, we stick a * in between each key to search for.
|
||||
This means that if the user enters words, they'll get
|
||||
"enters*words". If the user "enters words", they'll get
|
||||
"enters words" */
|
||||
|
||||
keyptr=keylist;
|
||||
while(keyptr!=NULL)
|
||||
{
|
||||
len+=strlen(keyptr->str)+1;
|
||||
keyptr=keyptr->next;
|
||||
}
|
||||
|
||||
searchkey=malloc(len+1);
|
||||
if(searchkey==NULL)
|
||||
goto fail;
|
||||
|
||||
searchkey[0]='\0';
|
||||
|
||||
keyptr=keylist;
|
||||
while(keyptr!=NULL)
|
||||
{
|
||||
strcat(searchkey,keyptr->str);
|
||||
strcat(searchkey,"*");
|
||||
keyptr=keyptr->next;
|
||||
}
|
||||
|
||||
/* Nail that last "*" */
|
||||
searchkey[strlen(searchkey)-1]='\0';
|
||||
|
||||
if(search_key(searchkey)==-1)
|
||||
{
|
||||
fprintf(output,"SEARCH %s FAILED\n",searchkey);
|
||||
failed++;
|
||||
}
|
||||
|
||||
free(searchkey);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(!failed)
|
||||
ret=KEYSERVER_OK;
|
||||
|
||||
fail:
|
||||
|
||||
while(keylist!=NULL)
|
||||
{
|
||||
struct keylist *current=keylist;
|
||||
keylist=keylist->next;
|
||||
free(current);
|
||||
}
|
||||
|
||||
if(input!=stdin)
|
||||
fclose(input);
|
||||
|
||||
if(output!=stdout)
|
||||
fclose(output);
|
||||
|
||||
if(ldap!=NULL)
|
||||
ldap_unbind_s(ldap);
|
||||
|
||||
free(basekeyspacedn);
|
||||
|
||||
return ret;
|
||||
}
|
164
keyserver/gpgkeys_mailto.in
Executable file
164
keyserver/gpgkeys_mailto.in
Executable file
|
@ -0,0 +1,164 @@
|
|||
#!@PERL@ -w
|
||||
|
||||
# gpgkeys_mailto - talk to a email keyserver
|
||||
# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GnuPG.
|
||||
#
|
||||
# GnuPG is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GnuPG is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
use Getopt::Std;
|
||||
$sendmail="@SENDMAIL@ -t";
|
||||
|
||||
###
|
||||
|
||||
getopts('o:');
|
||||
|
||||
if(defined($opt_o))
|
||||
{
|
||||
open(STDOUT,">$opt_o") || die "Can't open output file $opt_o\n";
|
||||
}
|
||||
|
||||
if(@ARGV)
|
||||
{
|
||||
open(STDIN,$ARGV[0]) || die "Can't open input file $ARGV[0]\n";
|
||||
}
|
||||
|
||||
($login,$name)=(getpwuid($<))[0,6];
|
||||
|
||||
while(<STDIN>)
|
||||
{
|
||||
last if($_ eq "\n");
|
||||
|
||||
if(/^COMMAND (\w+)/)
|
||||
{
|
||||
$command=$1;
|
||||
}
|
||||
|
||||
if(/^HOST (\S+)/)
|
||||
{
|
||||
$host=$1;
|
||||
}
|
||||
|
||||
if(/^OPTION (\w+)/)
|
||||
{
|
||||
if($1=~/^verbose$/i)
|
||||
{
|
||||
$verbose++;
|
||||
}
|
||||
elsif($1=~/^no-verbose$/i)
|
||||
{
|
||||
$verbose--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(<STDIN>)
|
||||
{
|
||||
last if($_ eq "\n");
|
||||
|
||||
chomp;
|
||||
|
||||
push(@keys,$_);
|
||||
}
|
||||
|
||||
# Send response
|
||||
|
||||
print "VERSION 0\n";
|
||||
print "OPTION OUTOFBAND\n\n";
|
||||
|
||||
# Email keyservers get and search the same way
|
||||
|
||||
if($command=~/get/i || $command=~/search/i)
|
||||
{
|
||||
if($command=~/search/i)
|
||||
{
|
||||
print "COUNT 0\n";
|
||||
}
|
||||
|
||||
foreach $key (@keys)
|
||||
{
|
||||
open(MAIL,"|$sendmail") || die "ERROR: Can't open $sendmail\n";
|
||||
print MAIL "From: $name <$login>\n";
|
||||
print MAIL "To: $host\n";
|
||||
if($command=~/get/i)
|
||||
{
|
||||
# mail keyservers don't like long-form keyids
|
||||
|
||||
if(substr($key,0,2) eq "0x")
|
||||
{
|
||||
$key=substr($key,2);
|
||||
}
|
||||
|
||||
if(length($key)>8)
|
||||
{
|
||||
$key=substr($key,-8);
|
||||
}
|
||||
|
||||
print MAIL "Subject: GET 0x$key\n\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print MAIL "Subject: GET $key\n\n";
|
||||
}
|
||||
print MAIL "GnuPG keyserver request\n";
|
||||
close(MAIL);
|
||||
|
||||
# Tell GnuPG not to expect a key
|
||||
print "KEY $key OUTOFBAND\n";
|
||||
|
||||
if($verbose)
|
||||
{
|
||||
print STDERR "gpgkeys: key $key requested from $host\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($command=~/send/i)
|
||||
{
|
||||
while(!eof(STDIN))
|
||||
{
|
||||
open(MAIL,"|$sendmail") || die "ERROR: Can't open $sendmail\n";
|
||||
print MAIL "From: $name <$login>\n";
|
||||
print MAIL "To: $host\n";
|
||||
print MAIL "Subject: ADD\n\n";
|
||||
|
||||
while(<STDIN>)
|
||||
{
|
||||
if(/^KEY (\w+) BEGIN$/)
|
||||
{
|
||||
$key=$1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
while(<STDIN>)
|
||||
{
|
||||
if(/^KEY \w+ END$/)
|
||||
{
|
||||
last;
|
||||
}
|
||||
|
||||
print MAIL;
|
||||
}
|
||||
|
||||
close(MAIL);
|
||||
|
||||
if($verbose)
|
||||
{
|
||||
print STDERR "gpgkeys: key $key sent to $host\n";
|
||||
}
|
||||
}
|
||||
}
|
79
keyserver/gpgkeys_test.in
Executable file
79
keyserver/gpgkeys_test.in
Executable file
|
@ -0,0 +1,79 @@
|
|||
#!@PERL@
|
||||
|
||||
# gpgkeys_test - keyserver code tester
|
||||
# Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GnuPG.
|
||||
#
|
||||
# GnuPG is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GnuPG is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
use Getopt::Std;
|
||||
|
||||
$|=1;
|
||||
|
||||
print STDERR "gpgkeys_test starting\n";
|
||||
|
||||
getopts('o:');
|
||||
|
||||
if(defined($opt_o))
|
||||
{
|
||||
print STDERR "Using output file $opt_o\n";
|
||||
open(STDOUT,">$opt_o") || die "Can't open output file $opt_o\n";
|
||||
}
|
||||
|
||||
if(@ARGV)
|
||||
{
|
||||
print STDERR "Using input file $ARGV[0]\n";
|
||||
open(STDIN,$ARGV[0]) || die "Can't open input file $ARGV[0]\n";
|
||||
}
|
||||
|
||||
# Get the command block
|
||||
|
||||
print STDERR "Command block:\n";
|
||||
|
||||
while(<STDIN>)
|
||||
{
|
||||
last if($_ eq "\n");
|
||||
print STDERR "--command-> $_";
|
||||
|
||||
if(/^COMMAND (\w+)/)
|
||||
{
|
||||
$command=$1;
|
||||
}
|
||||
}
|
||||
|
||||
# Get the keylist block
|
||||
|
||||
print STDERR "Keylist block:\n";
|
||||
|
||||
while(<STDIN>)
|
||||
{
|
||||
last if($_ eq "\n");
|
||||
print STDERR "--keylist-> $_";
|
||||
}
|
||||
|
||||
# If it's a SEND, then get the key material
|
||||
|
||||
if($command eq "SEND")
|
||||
{
|
||||
print STDERR "Key material to send:\n";
|
||||
|
||||
while(<STDIN>)
|
||||
{
|
||||
print STDERR "$_";
|
||||
}
|
||||
}
|
||||
|
||||
printf STDERR "gpgkeys_test finished\n";
|
Loading…
Add table
Add a link
Reference in a new issue