initial commit

This commit is contained in:
Luca Bilke 2022-09-28 09:39:54 +02:00
commit 960a606ff2
No known key found for this signature in database
GPG Key ID: 7B77C51E8C779E75
28 changed files with 6789 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
build
*.o

280
LICENSE Normal file
View File

@ -0,0 +1,280 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS

66
Makefile Normal file
View File

@ -0,0 +1,66 @@
# pinentry-dmenu - dmenu-like stupid pin entry
# See LICENSE file for copyright and license details.
include config.mk
SRC = pinentry-dmenu.c drw.c util.c
OBJ = ${SRC:.c=.o}
OBJ_PIN = pinentry/pinentry.o pinentry/util.o pinentry/password-cache.o pinentry/argparse.o pinentry/secmem.o
all: options pinentry-dmenu
options:
@echo pinentry-dmenu build options:
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}"
.c.o:
@echo CC $<
@${CC} -c ${CFLAGS} $<
config.h:
@echo creating $@ from config.def.h
@cp config.def.h $@
${OBJ}: config.h config.mk drw.h
pinentry:
$(MAKE) -C pinentry
pinentry-dmenu: pinentry pinentry-dmenu.o drw.o util.o
@echo CC -o $@
@${CC} -o $@ ${OBJ} ${OBJ_PIN} ${LDFLAGS} -lassuan -lgpgme -lgpg-error -lconfig
clean:
@echo cleaning
@rm -f pinentry-dmenu ${OBJ}
$(MAKE) -C pinentry/ clean
dist: clean
@echo creating dist tarball
@mkdir -p dmenu-${VERSION}
@cp LICENSE Makefile README arg.h config.def.h config.mk dmenu.1 \
drw.h util.h dmenu_path dmenu_run stest.1 ${SRC} \
dmenu-${VERSION}
@tar -cf dmenu-${VERSION}.tar dmenu-${VERSION}
@gzip dmenu-${VERSION}.tar
@rm -rf dmenu-${VERSION}
install: all
@echo installing executable to ${DESTDIR}${PREFIX}/bin
@mkdir -p ${DESTDIR}${PREFIX}/bin
@cp -f pinentry-dmenu ${DESTDIR}${PREFIX}/bin
@chmod 755 ${DESTDIR}${PREFIX}/bin/pinentry-dmenu
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
@sed "s/VERSION/${VERSION}/g;s/DATE/${DATE}/g;s/BUGREPORT/${BUGREPORT}/g" < pinentry-dmenu.1 > ${DESTDIR}${MANPREFIX}/man1/pinentry-dmenu.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/pinentry-dmenu.1
uninstall:
@echo removing executable from ${DESTDIR}${PREFIX}/bin
@rm -f ${DESTDIR}${PREFIX}/bin/pinentry-dmenu
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
@rm -f ${DESTDIR}${MANPREFIX}/man1/pinentry-dmenu.1
.PHONY: all options clean dist install pinentry uninstall

65
README.md Normal file
View File

@ -0,0 +1,65 @@
pinentry-dmenu
==============
pinentry-dmenu is a pinentry program with the charm of [dmenu](https://tools.suckless.org/dmenu).
This program is a fork from [spine](https://gitgud.io/zavok/spine.git) which is also a fork from [dmenu](https://tools.suckless.org/dmenu).
Requirements
------------
In order to build dmenu you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup (dmenu is installed into the /usr/local namespace by default).
Afterwards enter the following command to build and install dmenu
(if necessary as root):
make clean install
Config
------
To use pinentry-dmenu add in `~/.gnupg/gpg-agent.conf`:
pinentry-program <absolut path to pinentry-dmenu>
The config is located in `~/.gnupg/pinentry-dmenu.conf`.
Parameter | Default | Description
:------------------ |:----------------- |:-----------
asterisk | * | Defines the symbol which is showed for each typed character
bottom | false | pinentry-dmenu appears at the bottom of the screen
min_password_length | 32 | The minimal space of the password field. This value has affect to the description field after the password field
monitor | -1 | pinentry-dmenu is displayed on the monitor number supplied. Monitor numbers are starting from 0
prompt | "" | Defines the prompt to be displayed to the left of the input field
font | monospace:size=10 | Defines the font or font set used
prompt_bg | #bbbbbb | Defines the prompt background color
prompt_fg | #222222 | Defines the prompt foreground color
normal_bg | #bbbbbb | Defines the normal background color
normal_fg | #222222 | Defines the normal foreground color
select_bg | #eeeeee | Defines the selected background color
select_fg | #005577 | Defines the selected foreground color
desc_bg | #bbbbbb | Defines the description background color
desc_fg | #222222 | Defines the description foreground color
embedded | false | Embed into window
Example
-------
```
asterisk= "# ";
prompt = "$";
font = "Noto Sans UI:size=13";
prompt_fg = "#eeeeee";
prompt_bg = "#d9904a";
normal_fg = "#ffffff";
normal_bg = "#000000";
select_fg = "#eeeeee";
select_bg = "#d9904a";
desc_fg = "#eeeeee";
desc_bg = "#d9904a";
```

21
config.h Normal file
View File

@ -0,0 +1,21 @@
/* See LICENSE file for copyright and license details. */
/* Default settings; can be overriden by command line. */
static int bottom = 0;
static int embedded = 0;
static int minpwlen = 32;
static int mon = -1;
static int lineheight = 0;
static int min_lineheight = 8;
static const char *asterisk = "";
static const char *fonts[] = {
"NotoSans Nerd Font:style=Regular:pixelsize=14:antialias=true"
};
static const char *prompt = "";
static const char *colors[SchemeLast][4] = {
[SchemePrompt] = { "#c0caf5", "#15161E" },
[SchemeNormal] = { "#c0caf5", "#15161E" },
[SchemeSelect] = { "#15161E", "#7aa2f7" },
[SchemeDesc] = { "#a9b1d6", "#15161E" }
};

33
config.mk Normal file
View File

@ -0,0 +1,33 @@
# Pinentry settings
DATE = $$(date +'%B %Y')
VERSION = 0.1
BUGREPORT = https:\/\/github.com\/ritze\/pinentry-dmenu
# Paths
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# Xinerama, comment if you don't want it
XINERAMALIBS = -lXinerama
XINERAMAFLAGS = -DXINERAMA
# Freetype
FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2
# Includes and libs
INCS = -I${X11INC} -I${FREETYPEINC}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
# Flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} -DPACKAGE_VERSION=\"${VERSION}\" -DPACKAGE_BUGREPORT=\"${BUGREPORT}\"
CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
LDFLAGS = -s ${LIBS}
# Compiler and linker
CC = cc

421
drw.c Normal file
View File

@ -0,0 +1,421 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include "drw.h"
#include "util.h"
#define UTF_INVALID 0xFFFD
#define UTF_SIZ 4
static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
static long
utf8decodebyte(const char c, size_t *i)
{
for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
return (unsigned char)c & ~utfmask[*i];
return 0;
}
static size_t
utf8validate(long *u, size_t i)
{
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
*u = UTF_INVALID;
for (i = 1; *u > utfmax[i]; ++i)
;
return i;
}
static size_t
utf8decode(const char *c, long *u, size_t clen)
{
size_t i, j, len, type;
long udecoded;
*u = UTF_INVALID;
if (!clen)
return 0;
udecoded = utf8decodebyte(c[0], &len);
if (!BETWEEN(len, 1, UTF_SIZ))
return 1;
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
if (type)
return j;
}
if (j < len)
return 0;
*u = udecoded;
utf8validate(u, len);
return len;
}
Drw *
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
{
Drw *drw = ecalloc(1, sizeof(Drw));
drw->dpy = dpy;
drw->screen = screen;
drw->root = root;
drw->w = w;
drw->h = h;
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
drw->gc = XCreateGC(dpy, root, 0, NULL);
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
return drw;
}
void
drw_resize(Drw *drw, unsigned int w, unsigned int h)
{
if (!drw)
return;
drw->w = w;
drw->h = h;
if (drw->drawable)
XFreePixmap(drw->dpy, drw->drawable);
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
}
void
drw_free(Drw *drw)
{
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
free(drw);
}
/* This function is an implementation detail. Library users should use
* drw_fontset_create instead.
*/
static Fnt *
xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
{
Fnt *font;
XftFont *xfont = NULL;
FcPattern *pattern = NULL;
if (fontname) {
/* Using the pattern found at font->xfont->pattern does not yield the
* same substitution results as using the pattern returned by
* FcNameParse; using the latter results in the desired fallback
* behaviour whereas the former just results in missing-character
* rectangles being drawn, at least with some fonts. */
if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
return NULL;
}
if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
XftFontClose(drw->dpy, xfont);
return NULL;
}
} else if (fontpattern) {
if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
fprintf(stderr, "error, cannot load font from pattern.\n");
return NULL;
}
} else {
die("no font specified.");
}
font = ecalloc(1, sizeof(Fnt));
font->xfont = xfont;
font->pattern = pattern;
font->h = xfont->ascent + xfont->descent;
font->dpy = drw->dpy;
return font;
}
static void
xfont_free(Fnt *font)
{
if (!font)
return;
if (font->pattern)
FcPatternDestroy(font->pattern);
XftFontClose(font->dpy, font->xfont);
free(font);
}
Fnt*
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
{
Fnt *cur, *ret = NULL;
size_t i;
if (!drw || !fonts)
return NULL;
for (i = 1; i <= fontcount; i++) {
if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
cur->next = ret;
ret = cur;
}
}
return (drw->fonts = ret);
}
void
drw_fontset_free(Fnt *font)
{
if (font) {
drw_fontset_free(font->next);
xfont_free(font);
}
}
void
drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
{
if (!drw || !dest || !clrname)
return;
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen),
clrname, dest))
die("error, cannot allocate color '%s'", clrname);
}
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */
Clr *
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
{
size_t i;
Clr *ret;
/* need at least two colors for a scheme */
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
return NULL;
for (i = 0; i < clrcount; i++)
drw_clr_create(drw, &ret[i], clrnames[i]);
return ret;
}
void
drw_setfontset(Drw *drw, Fnt *set)
{
if (drw)
drw->fonts = set;
}
void
drw_setscheme(Drw *drw, Clr *scm)
{
if (drw)
drw->scheme = scm;
}
void
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
{
if (!drw || !drw->scheme)
return;
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
if (filled)
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
else
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
}
int
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
{
char buf[1024];
int ty;
unsigned int ew;
XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont;
size_t i, len;
int utf8strlen, utf8charlen, render = x || y || w || h;
long utf8codepoint = 0;
const char *utf8str;
FcCharSet *fccharset;
FcPattern *fcpattern;
FcPattern *match;
XftResult result;
int charexists = 0;
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
return 0;
if (!render) {
w = ~w;
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
d = XftDrawCreate(drw->dpy, drw->drawable,
DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen));
x += lpad;
w -= lpad;
}
usedfont = drw->fonts;
while (1) {
utf8strlen = 0;
utf8str = text;
nextfont = NULL;
while (*text) {
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) {
if (curfont == usedfont) {
utf8strlen += utf8charlen;
text += utf8charlen;
} else {
nextfont = curfont;
}
break;
}
}
if (!charexists || nextfont)
break;
else
charexists = 0;
}
if (utf8strlen) {
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
/* shorten text if necessary */
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
if (len) {
memcpy(buf, utf8str, len);
buf[len] = '\0';
if (len < utf8strlen)
for (i = len; i && i > len - 3; buf[--i] = '.')
; /* NOP */
if (render) {
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
usedfont->xfont, x, ty, (XftChar8 *)buf, len);
}
x += ew;
w -= ew;
}
}
if (!*text) {
break;
} else if (nextfont) {
charexists = 0;
usedfont = nextfont;
} else {
/* Regardless of whether or not a fallback font is found, the
* character must be drawn. */
charexists = 1;
fccharset = FcCharSetCreate();
FcCharSetAddChar(fccharset, utf8codepoint);
if (!drw->fonts->pattern) {
/* Refer to the comment in xfont_create for more information. */
die("the first font in the cache must be loaded from a font string.");
}
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
FcDefaultSubstitute(fcpattern);
match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
FcCharSetDestroy(fccharset);
FcPatternDestroy(fcpattern);
if (match) {
usedfont = xfont_create(drw, NULL, match);
if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
; /* NOP */
curfont->next = usedfont;
} else {
xfont_free(usedfont);
usedfont = drw->fonts;
}
}
}
}
if (d)
XftDrawDestroy(d);
return x + (render ? w : 0);
}
void
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
{
if (!drw)
return;
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
XSync(drw->dpy, False);
}
unsigned int
drw_fontset_getwidth(Drw *drw, const char *text)
{
if (!drw || !drw->fonts || !text)
return 0;
return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
}
void
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
{
XGlyphInfo ext;
if (!font || !text)
return;
XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
if (w)
*w = ext.xOff;
if (h)
*h = font->h;
}
Cur *
drw_cur_create(Drw *drw, int shape)
{
Cur *cur;
if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
return NULL;
cur->cursor = XCreateFontCursor(drw->dpy, shape);
return cur;
}
void
drw_cur_free(Drw *drw, Cur *cursor)
{
if (!cursor)
return;
XFreeCursor(drw->dpy, cursor->cursor);
free(cursor);
}

57
drw.h Normal file
View File

@ -0,0 +1,57 @@
/* See LICENSE file for copyright and license details. */
typedef struct {
Cursor cursor;
} Cur;
typedef struct Fnt {
Display *dpy;
unsigned int h;
XftFont *xfont;
FcPattern *pattern;
struct Fnt *next;
} Fnt;
enum { ColFg, ColBg }; /* Clr scheme index */
typedef XftColor Clr;
typedef struct {
unsigned int w, h;
Display *dpy;
int screen;
Window root;
Drawable drawable;
GC gc;
Clr *scheme;
Fnt *fonts;
} Drw;
/* Drawable abstraction */
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
void drw_free(Drw *drw);
/* Fnt abstraction */
Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
void drw_fontset_free(Fnt* set);
unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
/* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
/* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape);
void drw_cur_free(Drw *drw, Cur *cursor);
/* Drawing context manipulation */
void drw_setfontset(Drw *drw, Fnt *set);
void drw_setscheme(Drw *drw, Clr *scm);
/* Drawing functions */
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
/* Map functions */
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);

228
pinentry-dmenu.1 Normal file
View File

@ -0,0 +1,228 @@
.TH PINENTRY-DMENU 1 "DATE" pinentry-dmenu\-VERSION "pinentry-dmenu Manual"
.SH NAME
pinentry-dmenu - a pinentry program with the charm of dmenu
.SH DESCRIPTION
.B pinentry-dmenu
is a dmenu- and pinentry-based passphrase dialog called from the
.BR gpg-agent (1)
daemon. It is not intended to be invoked directly.
.SH SYNOPSIS
Set the
.B pinentry-program
in
.IR ~/.gnupg/gpg-agent.conf
to
.B pinentry-dmenu
to use the program as the regular dialog for
.BR gpg-agent .
.PP
The configuration is placed in
.IR ~/.gnupg/pinentry-dmenu.conf .
You can change the path to the config file with the environment variable
.IR GNUPGHOME .
.SH OPTIONS
.TP
.BI "asterisk =" " *"
Defines the symbol which is showed for each typed character.
.TP
.BI "bottom =" " false"
pinentry-dmenu appears at the bottom of the screen.
.TP
.BI "min_password_length =" " 32"
The minimal space of the password field. This value has affect to the description field after the password field.
.TP
.BI "height =" " 8"
Height of pinentry-dmenu in pixels (no less than 8)
.TP
.BI "monitor =" " -1"
pinentry-dmenu is displayed on the monitor number supplied. Monitor numbers are starting from 0.
.TP
.BI "prompt =" " """"
Defines the prompt to be displayed to the left of the input field.
.TP
.BI "font =" " monospace:size=10"
Defines the font or font set used.
.TP
.BI "prompt_bg =" " #bbbbbb"
Defines the prompt background color.
.IR #RGB ,
.I #RRGGBB
and X color names are supported.
.TP
.BI "prompt_fg =" " #222222"
Defines the prompt foreground color.
.TP
.BI "normal_bg =" " #bbbbbb"
Defines the normal background color.
.TP
.BI "normal_fg =" " #222222"
Defines the normal foreground color.
.TP
.BI "select_bg =" " #eeeeee"
Defines the selected background color.
.TP
.BI "select_fg =" " #005577"
Defines the selected foreground color.
.TP
.BI "desc_bg =" " #bbbbbb"
Defines the description background color.
.TP
.BI "desc_fg =" " #222222"
Defines the description foreground color.
.TP
.BI "embedded =" " false"
Embed into window.
.SH USAGE
pinentry-dmenu is completely controlled by the keyboard.
.TP
.B Return
Confirm input
.TP
.B Ctrl-Return
Confirm input
.TP
.B Shift\-Return
Confirm input
.TP
.B Escape
Cancel input
.TP
.B C\-c
Escape
.SS Confirm Mode
.TP
.B Down
Right
.TP
.B End
Right
.TP
.B Home
Left
.TP
.B Next
Right
.TP
.B Prior
Left
.TP
.B Up
Left
.TP
.B g
Cancel input
.TP
.B G
Cancel input
.TP
.B h
Left
.TP
.B j
Left
.TP
.B k
Right
.TP
.B l
Right
.TP
.B n
Confirm with no
.TP
.B N
Confirm with no
.TP
.B y
Confirm with yes
.TP
.B Y
Confirm with yes
.SS Pin Mode
.TP
.B End
Move cursor to the line end
.TP
.B Home
Move cursor to the line begin
.TP
.B C\-a
Home
.TP
.B C\-b
Left
.TP
.B C\-d
Delete
.TP
.B C\-e
End
.TP
.B C\-f
Right
.TP
.B C\-g
Escape
.TP
.B C\-h
Backspace
.TP
.B C\-k
Delete line right
.TP
.B C\-u
Delete line left
.TP
.B C\-v
Paste from primary X selection
.SH EXAMPLES
.sp
.if n \{
.RS 4
.\}
.nf
asterisk= "# ";
prompt = "$";
font = "Noto Sans UI:size=13";
prompt_fg = "#eeeeee";
prompt_bg = "#d9904a";
normal_fg = "#ffffff";
normal_bg = "#000000";
select_fg = "#eeeeee";
select_bg = "#d9904a";
desc_fg = "#eeeeee";
desc_bg = "#d9904a";
.SH AUTHORS
.B pinentry-dmenu
is a fork of
.B dmenu
<https://tools.suckless.org/dmenu>
and uses the api of
.B pinentry
, a GnuPG tool.
.B pinentry-dmenu
itself was written by Moritz Lüdecke <ritze@skweez.net>.
.SH REPORTING BUGS
Report pinentry-dmenu bugs to <BUGREPORT>
.SH SEE ALSO
.BR dmenu (1),
.BR dwm (1),
.BR gpg-agent (1)

803
pinentry-dmenu.c Normal file
View File

@ -0,0 +1,803 @@
/* See LICENSE file for copyright and license details. */
#include <ctype.h>
#include <libconfig.h>
#include <locale.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <pwd.h>
#include <time.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif
#include <X11/Xft/Xft.h>
#include "drw.h"
#include "util.h"
#include "pinentry/pinentry.h"
#include "pinentry/memory.h"
#define CONFIG_DIR "/.gnupg"
#define CONFIG_FILE "/pinentry-dmenu.conf"
#define INTERSECT(x, y, w, h, r) \
(MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \
&& MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
#define LENGTH(X) (sizeof(X) / sizeof(X[0]))
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
#define MINDESCLEN 8
enum { SchemePrompt, SchemeNormal, SchemeSelect, SchemeDesc, SchemeLast };
enum { WinPin, WinConfirm };
enum { Ok, NotOk, Cancel };
enum { Nothing, Yes, No };
static int bh, mw, mh;
static int sel;
static int promptw, pdescw;
/* Sum of left and right padding */
static int lrpad;
static size_t cursor;
static int screen;
static char* pin;
static int pin_len;
static char* pin_repeat;
static int pin_repeat_len;
static int repeat;
static Atom clip, utf8;
static Display *dpy;
static Window root, parentwin, win;
static XIC xic;
static Drw *drw;
static Clr *scheme[SchemeLast];
static int timed_out;
static int winmode;
pinentry_t pinentry_info;
#include "config.h"
static int
drawitem(const char* text, Bool sel, int x, int y, int w) {
unsigned int i = (sel) ? SchemeSelect : SchemeNormal;
drw_setscheme(drw, scheme[i]);
return drw_text(drw, x, y, w, bh, lrpad / 2, text, 0);
}
static void
grabfocus(void) {
Window focuswin;
int i, revertwin;
for (i = 0; i < 100; ++i) {
XGetInputFocus(dpy, &focuswin, &revertwin);
if (focuswin == win) {
return;
}
XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
usleep(1000);
}
die("cannot grab focus");
}
static void
grabkeyboard(void) {
int i;
if (embedded) {
return;
}
/* Try to grab keyboard,
* we may have to wait for another process to ungrab */
for (i = 0; i < 1000; i++) {
if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync,
GrabModeAsync, CurrentTime) == GrabSuccess) {
return;
}
usleep(1000);
}
die("cannot grab keyboard");
}
static size_t
nextrune(int cursor, int inc) {
ssize_t n;
/* Return location of next utf8 rune in the given direction (+1 or -1) */
for (n = cursor + inc;
n + inc >= 0 && (pin[n] & 0xc0) == 0x80;
n += inc);
return n;
}
static void
setup_pin(char* pin_ptr, int len, int reset) {
pin = pin_ptr;
pin_len = len;
if (reset) {
promptw = (prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
cursor = 0;
if (pin) {
pin[0] = '\0';
}
}
}
static void
insert(const char *str, ssize_t n) {
size_t len = strlen(pin);
// FIXME: Pinentry crashes when increasing the pin buffer the second time.
// Other pinentry programs has a limited passwort field length.
if (len + n > pin_len - 1) {
if (repeat) {
pin_repeat_len = 2 * pin_repeat_len;
pin_repeat = secmem_realloc(pin_repeat, pin_repeat_len);
setup_pin(pin_repeat, pin_repeat_len, 0);
if (!pin_repeat) {
pin_len = 0;
}
} else {
if (!pinentry_setbufferlen(pinentry_info, 2 * pinentry_info->pin_len)) {
pin_len = 0;
} else {
setup_pin(pinentry_info->pin, pinentry_info->pin_len, 0);
}
}
if (pin_len == 0) {
printf("Error: Couldn't allocate secure memory\n");
return;
}
}
/* Move existing text out of the way, insert new text, and update cursor */
memmove(&pin[cursor + n], &pin[cursor], pin_len - cursor - MAX(n, 0));
if (n > 0) {
memcpy(&pin[cursor], str, n);
}
cursor += n;
pin[len + n] = '\0';
}
static void
drawwin(void) {
unsigned int curpos;
int x = 0, fh = drw->fonts->h, pb, pbw = 0, i;
size_t asterlen = strlen(asterisk);
size_t pdesclen;
int leftinput;
char* censort;
char* pprompt = (repeat) ? pinentry_info->repeat_passphrase : pinentry_info->prompt;
int ppromptw = (pprompt) ? TEXTW(pprompt) : 0;
unsigned int censortl = minpwlen * TEXTW(asterisk) / strlen(asterisk);
unsigned int confirml = TEXTW(" YesNo ") + 3 * lrpad;
drw_setscheme(drw, scheme[SchemeNormal]);
drw_rect(drw, 0, 0, mw, mh, 1, 1);
if (prompt) {
drw_setscheme(drw, scheme[SchemePrompt]);
x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0);
}
if (pprompt) {
drw_setscheme(drw, scheme[SchemePrompt]);
drw_text(drw, x, 0, ppromptw, bh, lrpad / 2, pprompt, 0);
x += ppromptw;
}
if (pinentry_info->description) {
pb = mw - x;
pdesclen = strlen(pinentry_info->description);
if (pb > 0) {
pb -= (winmode == WinPin) ? censortl : confirml;
pbw = MINDESCLEN * pdescw / pdesclen;
pbw = MIN(pbw, pdescw);
if (pb >= pbw) {
pbw = MAX(pbw, pdescw);
pbw = MIN(pbw, pb);
pb = mw - pbw;
for (i = 0; i < pdesclen; i++) {
if (pinentry_info->description[i] == '\n') {
pinentry_info->description[i] = ' ';
}
}
drw_setscheme(drw, scheme[SchemeDesc]);
drw_text(drw, pb, 0, pbw, bh, lrpad / 2, pinentry_info->description,
0);
} else {
pbw = 0;
}
}
}
/* Draw input field */
drw_setscheme(drw, scheme[SchemeNormal]);
if (winmode == WinPin) {
censort = ecalloc(1, asterlen * pin_len);
for (i = 0; i < asterlen * strlen(pin); i += asterlen) {
memcpy(&censort[i], asterisk, asterlen);
}
censort[i+1] = '\n';
leftinput = mw - x - pbw;
drw_text(drw, x, 0, leftinput, bh, lrpad / 2, censort, 0);
drw_font_getexts(drw->fonts, censort, cursor * asterlen, &curpos, NULL);
if ((curpos += lrpad / 2 - 1) < leftinput) {
drw_setscheme(drw, scheme[SchemeNormal]);
drw_rect(drw, x + curpos, 2 + (bh - fh) / 2, 2, fh - 4, 1, 0);
}
free(censort);
} else {
x += TEXTW(" ");
x = drawitem("No", (sel == No), x, 0, TEXTW("No"));
x = drawitem("Yes", (sel == Yes), x, 0, TEXTW("Yes"));
}
drw_map(drw, win, 0, 0, mw, mh);
}
static void
setup(void) {
int x, y, i = 0;
unsigned int du;
XSetWindowAttributes swa;
XIM xim;
Window w, dw, *dws;
XWindowAttributes wa;
#ifdef XINERAMA
XineramaScreenInfo *info;
Window pw;
int a, j, di, n, area = 0;
#endif
/* Init appearance */
scheme[SchemePrompt] = drw_scm_create(drw, colors[SchemePrompt], 2);
scheme[SchemeNormal] = drw_scm_create(drw, colors[SchemeNormal], 2);
scheme[SchemeSelect] = drw_scm_create(drw, colors[SchemeSelect], 2);
scheme[SchemeDesc] = drw_scm_create(drw, colors[SchemeDesc], 2);
clip = XInternAtom(dpy, "CLIPBOARD", False);
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
/* Calculate menu geometry */
bh = drw->fonts->h + 2;
bh = MAX(bh, lineheight);
mh = bh;
#ifdef XINERAMA
info = XineramaQueryScreens(dpy, &n);
if (parentwin == root && info) {
XGetInputFocus(dpy, &w, &di);
if (mon >= 0 && mon < n) {
i = mon;
} else if (w != root && w != PointerRoot && w != None) {
/* Find top-level window containing current input focus */
do {
if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) {
XFree(dws);
}
} while (w != root && w != pw);
/* Find xinerama screen with which the window intersects most */
if (XGetWindowAttributes(dpy, pw, &wa)) {
for (j = 0; j < n; j++) {
a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j]);
if (a > area) {
area = a;
i = j;
}
}
}
}
/* No focused window is on screen, so use pointer location instead */
if (mon < 0 && !area
&& XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) {
for (i = 0; i < n; i++) {
if (INTERSECT(x, y, 1, 1, info[i])) {
break;
}
}
}
x = info[i].x_org;
y = info[i].y_org + (bottom ? info[i].height - mh : 0);
mw = info[i].width;
XFree(info);
} else
#endif
{
if (!XGetWindowAttributes(dpy, parentwin, &wa)) {
die("could not get embedding window attributes: 0x%lx", parentwin);
}
x = 0;
y = bottom ? wa.height - mh : 0;
mw = wa.width;
}
pdescw = (pinentry_info->description) ? TEXTW(pinentry_info->description) : 0;
/* Create menu window */
swa.override_redirect = True;
swa.background_pixel = scheme[SchemePrompt][ColBg].pixel;
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
/* Open input methods */
xim = XOpenIM(dpy, NULL, NULL, NULL);
xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, win, XNFocusWindow, win, NULL);
XMapRaised(dpy, win);
if (embedded) {
XSelectInput(dpy, parentwin, FocusChangeMask);
if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
for (i = 0; i < du && dws[i] != win; ++i) {
XSelectInput(dpy, dws[i], FocusChangeMask);
}
XFree(dws);
}
grabfocus();
}
drw_resize(drw, mw, mh);
}
static void
cleanup(void) {
XUngrabKey(dpy, AnyKey, AnyModifier, root);
free(scheme[SchemeDesc]);
free(scheme[SchemeSelect]);
free(scheme[SchemeNormal]);
free(scheme[SchemePrompt]);
drw_free(drw);
XSync(dpy, False);
XCloseDisplay(dpy);
}
static int
keypress_confirm(XKeyEvent *ev, KeySym ksym) {
if (ev->state & ControlMask) {
switch(ksym) {
case XK_c:
pinentry_info->canceled = 1;
sel = No;
return 1;
default:
return 1;
}
}
switch(ksym) {
case XK_KP_Enter:
case XK_Return:
if (sel != Nothing) {
return 1;
}
break;
case XK_y:
case XK_Y:
sel = Yes;
return 1;
case XK_n:
case XK_N:
sel = No;
return 1;
case XK_g:
case XK_G:
case XK_Escape:
pinentry_info->canceled = 1;
sel = No;
return 1;
case XK_h:
case XK_j:
case XK_Home:
case XK_Left:
case XK_Prior:
case XK_Up:
sel = No;
break;
case XK_k:
case XK_l:
case XK_Down:
case XK_End:
case XK_Next:
case XK_Right:
sel = Yes;
break;
}
return 0;
}
static int
keypress_pin(XKeyEvent *ev, KeySym ksym, char* buf, int len) {
int old;
if (ev->state & ControlMask) {
switch(ksym) {
case XK_a: ksym = XK_Home; break;
case XK_b: ksym = XK_Left; break;
case XK_c: ksym = XK_Escape; break;
case XK_d: ksym = XK_Delete; break;
case XK_e: ksym = XK_End; break;
case XK_f: ksym = XK_Right; break;
case XK_g: ksym = XK_Escape; break;
case XK_h: ksym = XK_BackSpace; break;
case XK_k:
old = cursor;
cursor = strlen(pin);
insert(NULL, old - cursor);
break;
case XK_u:
insert(NULL, -cursor);
break;
case XK_v:
XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
utf8, utf8, win, CurrentTime);
return 0;
case XK_Return:
case XK_KP_Enter:
break;
case XK_bracketleft:
pinentry_info->canceled = 1;
return 1;
default:
return 1;
}
}
switch(ksym) {
case XK_Delete:
if (pin[cursor] == '\0') {
return 0;
}
cursor = nextrune(cursor, +1);
/* Fallthrough */
case XK_BackSpace:
if (cursor == 0) {
return 0;
}
insert(NULL, nextrune(cursor, -1) - cursor);
break;
case XK_Escape:
pinentry_info->canceled = 1;
return 1;
case XK_Left:
if (cursor > 0) {
cursor = nextrune(cursor, -1);
}
break;
case XK_Right:
if (pin[cursor] != '\0') {
cursor = nextrune(cursor, +1);
}
break;
case XK_Home:
cursor = 0;
break;
case XK_End:
cursor = strlen(pin);
break;
case XK_Return:
case XK_KP_Enter:
return 1;
break;
default:
if (!iscntrl(*buf)) {
insert(buf, len);
}
}
return 0;
}
static int
keypress(XKeyEvent *ev) {
char buf[32];
int len;
int ret = 1;
KeySym ksym = NoSymbol;
Status status;
len = XmbLookupString(xic, ev, buf, sizeof(buf), &ksym, &status);
if (status != XBufferOverflow) {
if (winmode == WinConfirm) {
ret = keypress_confirm(ev, ksym);
} else {
ret = keypress_pin(ev, ksym, buf, len);
}
if (ret == 0) {
drawwin();
}
}
return ret;
}
static void
paste(void) {
char *p, *q;
int di;
unsigned long dl;
Atom da;
/* We have been given the current selection, now insert it into input */
XGetWindowProperty(dpy, win, utf8, 0, pin_len / 4, False, utf8, &da, &di,
&dl, &dl, (unsigned char **)&p);
insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t) strlen(p));
XFree(p);
drawwin();
}
void
run(void) {
XEvent ev;
drawwin();
while (!XNextEvent(dpy, &ev)) {
if (XFilterEvent(&ev, win)) {
continue;
}
switch(ev.type) {
case Expose:
if (ev.xexpose.count == 0) {
drw_map(drw, win, 0, 0, mw, mh);
}
break;
case KeyPress:
if (keypress(&ev.xkey)) {
return;
}
break;
case SelectionNotify:
if (ev.xselection.property == utf8) {
paste();
}
break;
case VisibilityNotify:
if (ev.xvisibility.state != VisibilityUnobscured) {
XRaiseWindow(dpy, win);
}
break;
}
}
}
static void
catchsig(int sig) {
if (sig == SIGALRM) {
timed_out = 1;
}
}
static void
password(void) {
winmode = WinPin;
repeat = 0;
setup_pin(pinentry_info->pin, pinentry_info->pin_len, 1);
run();
if (!pinentry_info->canceled && pinentry_info->repeat_passphrase) {
repeat = 1;
pin_repeat_len = pinentry_info->pin_len;
pin_repeat = secmem_malloc(pinentry_info->pin_len);
setup_pin(pin_repeat, pin_repeat_len, 1);
run();
pinentry_info->repeat_okay = (strcmp(pinentry_info->pin, pin_repeat) == 0)? 1 : 0;
secmem_free(pin_repeat);
if (!pinentry_info->repeat_okay) {
pinentry_info->result = -1;
return;
}
}
if (pinentry_info->canceled) {
pinentry_info->result = -1;
return;
}
pinentry_info->result = strlen(pinentry_info->pin);
}
static void
confirm(void) {
winmode = WinConfirm;
sel = Nothing;
run();
pinentry_info->result = sel != No;
}
static int
cmdhandler(pinentry_t received_pinentry) {
struct sigaction sa;
XWindowAttributes wa;
pinentry_info = received_pinentry;
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) {
fputs("warning: no locale support\n", stderr);
}
if (!(dpy = XOpenDisplay(pinentry_info->display))) {
die("cannot open display");
}
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
embedded = (pinentry_info->parent_wid) ? embedded : 0;
parentwin = (embedded) ? pinentry_info->parent_wid : root;
if (!XGetWindowAttributes(dpy, parentwin, &wa)) {
die("could not get embedding window attributes: 0x%lx", parentwin);
}
drw = drw_create(dpy, screen, root, wa.width, wa.height);
if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) {
die("no fonts could be loaded.");
}
lrpad = drw->fonts->h;
drw_setscheme(drw, scheme[SchemePrompt]);
if (pinentry_info->timeout) {
memset(&sa, 0, sizeof(sa));
sa.sa_handler = catchsig;
sigaction(SIGALRM, &sa, NULL);
alarm(pinentry_info->timeout);
}
grabkeyboard();
setup();
if (pinentry_info->pin) {
do {
password();
} while (!pinentry_info->canceled && pinentry_info->repeat_passphrase
&& !pinentry_info->repeat_okay);
} else {
confirm();
}
cleanup();
return pinentry_info->result;
}
pinentry_cmd_handler_t pinentry_cmd_handler = cmdhandler;
int
main(int argc, char *argv[]) {
Bool bval;
int i, val;
const char *str;
struct passwd *pw;
char path[PATH_MAX];
char *sudo_uid = getenv("SUDO_UID");
char *home = getenv("HOME");
char *gnupghome = getenv("GNUPGHOME");
config_t cfg;
if (gnupghome) {
i = strlen(gnupghome);
strcpy(path, gnupghome);
} else {
/* Get the home dir even if the user used sudo or logged in as root */
if (sudo_uid) {
i = atoi(sudo_uid);
pw = getpwuid(i);
home = pw->pw_dir;
}
i = strlen(home);
strcpy(path, home);
strcpy(&path[i], CONFIG_DIR);
i += strlen(CONFIG_DIR);
}
strcpy(&path[i], CONFIG_FILE);
endpwent();
config_init(&cfg);
/* Read the file. If there is an error, report it and exit. */
if (config_read_file(&cfg, path)) {
if (config_lookup_string(&cfg, "asterisk", &str)) {
asterisk = str;
}
if (config_lookup_bool(&cfg, "bottom", &bval)) {
bottom = bval;
}
if (config_lookup_int(&cfg, "min_password_length", &val)) {
minpwlen = val;
}
if (config_lookup_int(&cfg, "height", &val)) {
lineheight = MAX(val, min_lineheight);
}
if (config_lookup_int(&cfg, "monitor", &val)) {
mon = val;
}
if (config_lookup_string(&cfg, "prompt", &str)) {
prompt = str;
}
if (config_lookup_string(&cfg, "font", &str)) {
fonts[0] = str;
}
if (config_lookup_string(&cfg, "prompt_bg", &str)) {
colors[SchemePrompt][ColBg] = str;
}
if (config_lookup_string(&cfg, "prompt_fg", &str)) {
colors[SchemePrompt][ColFg] = str;
}
if (config_lookup_string(&cfg, "normal_bg", &str)) {
colors[SchemeNormal][ColBg] = str;
}
if (config_lookup_string(&cfg, "normal_fg", &str)) {
colors[SchemeNormal][ColFg] = str;
}
if (config_lookup_string(&cfg, "select_bg", &str)) {
colors[SchemeSelect][ColBg] = str;
}
if (config_lookup_string(&cfg, "select_fg", &str)) {
colors[SchemeSelect][ColFg] = str;
}
if (config_lookup_string(&cfg, "desc_bg", &str)) {
colors[SchemeDesc][ColBg] = str;
}
if (config_lookup_string(&cfg, "desc_fg", &str)) {
colors[SchemeDesc][ColFg] = str;
}
if (config_lookup_bool(&cfg, "embedded", &bval)) {
embedded = bval;
}
} else if ((str = config_error_file(&cfg))) {
fprintf(stderr, "%s:%d: %s\n", config_error_file(&cfg),
config_error_line(&cfg), config_error_text(&cfg));
return(EXIT_FAILURE);
}
pinentry_init("pinentry-dmenu");
pinentry_parse_opts(argc, argv);
if (pinentry_loop()) {
return 1;
}
config_destroy(&cfg);
return 0;
}

11
pinentry/AUTHORS Normal file
View File

@ -0,0 +1,11 @@
Program: Pinentry
Bug reports: <gpa-dev@gnupg.org>
Security related bug reports: <security@gnupg.org>
License: GPLv2+
Robert Bihlmeyer <robbe@orcus.priv.at>
Werner Koch, g10 Code GmbH <wk@gnupg.org>
Steffen Hansen, Klarälvdalens Datakonsult AB <steffen@klaralvdalens-datakonsult.se>
Marcus Brinkmann, g10 Code GmbH <marcus@g10code.com>
Timo Schulz, g10 Code GmbH
Neal Walfied, g10 Code GmbH <neal@gnu.org>

280
pinentry/COPYING Normal file
View File

@ -0,0 +1,280 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS

21
pinentry/Makefile Normal file
View File

@ -0,0 +1,21 @@
include ../config.mk
SRC = util.c pinentry.c argparse.c password-cache.c secmem.c
OBJ = ${SRC:.c=.o}
CFLAGS += -DHAVE_MLOCK
all: pinentry
.c.o:
@echo CC $<
@${CC} -c ${CFLAGS} $<
${OBJ}: pinentry.h argparse.h password-cache.h memory.h util.h
pinentry: pinentry.o argparse.o password-cache.o secmem.o util.o
clean:
@echo cleaning
@rm -f ${OBJ}
.PHONY: all clean pinentry

1607
pinentry/argparse.c Normal file

File diff suppressed because it is too large Load Diff

203
pinentry/argparse.h Normal file
View File

@ -0,0 +1,203 @@
/* argparse.h - Argument parser for option handling.
* Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc.
*
* This file is part of JNLIB, which is a subsystem of GnuPG.
*
* JNLIB is free software; you can redistribute it and/or modify it
* under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* or
*
* - 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.
*
* or both in parallel, as here.
*
* JNLIB 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 copies of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBJNLIB_ARGPARSE_H
#define LIBJNLIB_ARGPARSE_H
#include <stdio.h>
typedef struct
{
int *argc; /* Pointer to ARGC (value subject to change). */
char ***argv; /* Pointer to ARGV (value subject to change). */
unsigned int flags; /* Global flags. May be set prior to calling the
parser. The parser may change the value. */
int err; /* Print error description for last option.
Either 0, ARGPARSE_PRINT_WARNING or
ARGPARSE_PRINT_ERROR. */
int r_opt; /* Returns option code. */
int r_type; /* Returns type of option value. */
union {
int ret_int;
long ret_long;
unsigned long ret_ulong;
char *ret_str;
} r; /* Return values */
struct {
int idx;
int inarg;
int stopped;
const char *last;
void *aliases;
const void *cur_alias;
void *iio_list;
} internal; /* Private - do not change. */
} ARGPARSE_ARGS;
typedef struct
{
int short_opt;
const char *long_opt;
unsigned int flags;
const char *description; /* Optional option description. */
} ARGPARSE_OPTS;
/* Global flags (ARGPARSE_ARGS). */
#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */
#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return
remaining args with R_OPT set to -1. */
#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */
#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */
#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */
#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */
#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */
#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */
/* Flags for each option (ARGPARSE_OPTS). The type code may be
ORed with the OPT flags. */
#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */
#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */
#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */
#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */
#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */
#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */
#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */
#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */
#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */
#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values (internal). */
/* A set of macros to make option definitions easier to read. */
#define ARGPARSE_x(s,l,t,f,d) \
{ (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) }
#define ARGPARSE_s(s,l,t,d) \
{ (s), (l), ARGPARSE_TYPE_ ## t, (d) }
#define ARGPARSE_s_n(s,l,d) \
{ (s), (l), ARGPARSE_TYPE_NONE, (d) }
#define ARGPARSE_s_i(s,l,d) \
{ (s), (l), ARGPARSE_TYPE_INT, (d) }
#define ARGPARSE_s_s(s,l,d) \
{ (s), (l), ARGPARSE_TYPE_STRING, (d) }
#define ARGPARSE_s_l(s,l,d) \
{ (s), (l), ARGPARSE_TYPE_LONG, (d) }
#define ARGPARSE_s_u(s,l,d) \
{ (s), (l), ARGPARSE_TYPE_ULONG, (d) }
#define ARGPARSE_o(s,l,t,d) \
{ (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) }
#define ARGPARSE_o_n(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) }
#define ARGPARSE_o_i(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) }
#define ARGPARSE_o_s(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) }
#define ARGPARSE_o_l(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) }
#define ARGPARSE_o_u(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) }
#define ARGPARSE_p(s,l,t,d) \
{ (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_p_n(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_p_i(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_p_s(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_p_l(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_p_u(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_op(s,l,t,d) \
{ (s), (l), (ARGPARSE_TYPE_ ## t \
| ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_op_n(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_NONE \
| ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_op_i(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_INT \
| ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_op_s(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_STRING \
| ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_op_l(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_LONG \
| ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_op_u(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_ULONG \
| ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
#define ARGPARSE_c(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) }
#define ARGPARSE_ignore(s,l) \
{ (s), (l), (ARGPARSE_OPT_IGNORE), "@" }
#define ARGPARSE_group(s,d) \
{ (s), NULL, 0, (d) }
#define ARGPARSE_end() { 0, NULL, 0, NULL }
/* Other constants. */
#define ARGPARSE_PRINT_WARNING 1
#define ARGPARSE_PRINT_ERROR 2
/* Error values. */
#define ARGPARSE_IS_ARG (-1)
#define ARGPARSE_INVALID_OPTION (-2)
#define ARGPARSE_MISSING_ARG (-3)
#define ARGPARSE_KEYWORD_TOO_LONG (-4)
#define ARGPARSE_READ_ERROR (-5)
#define ARGPARSE_UNEXPECTED_ARG (-6)
#define ARGPARSE_INVALID_COMMAND (-7)
#define ARGPARSE_AMBIGUOUS_OPTION (-8)
#define ARGPARSE_AMBIGUOUS_COMMAND (-9)
#define ARGPARSE_INVALID_ALIAS (-10)
#define ARGPARSE_OUT_OF_CORE (-11)
#define ARGPARSE_INVALID_ARG (-12)
int arg_parse (ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
int optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
void usage (int level);
const char *strusage (int level);
void set_strusage (const char *(*f)( int ));
void argparse_register_outfnc (int (*fnc)(int, const char *));
#endif /*LIBJNLIB_ARGPARSE_H*/

55
pinentry/memory.h Normal file
View File

@ -0,0 +1,55 @@
/* Quintuple Agent secure memory allocation
* Copyright (C) 1998,1999 Free Software Foundation, Inc.
* Copyright (C) 1999,2000 Robert Bihlmeyer <robbe@orcus.priv.at>
*
* This program 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.
*
* This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _MEMORY_H
#define _MEMORY_H
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#if 0
}
#endif
#endif
/* values for flags, hardcoded in secmem.c */
#define SECMEM_WARN 0
#define SECMEM_DONT_WARN 1
#define SECMEM_SUSPEND_WARN 2
void secmem_init( size_t npool );
void secmem_term( void );
void *secmem_malloc( size_t size );
void *secmem_realloc( void *a, size_t newsize );
void secmem_free( void *a );
int m_is_secure( const void *p );
void secmem_dump_stats(void);
void secmem_set_flags( unsigned flags );
unsigned secmem_get_flags(void);
size_t secmem_get_max_size (void);
#if 0
{
#endif
#ifdef __cplusplus
}
#endif
#endif /* _MEMORY_H */

163
pinentry/password-cache.c Normal file
View File

@ -0,0 +1,163 @@
/* password-cache.c - Password cache support.
Copyright (C) 2015 g10 Code GmbH
This file is part of PINENTRY.
PINENTRY 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.
PINENTRY 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_LIBSECRET
# include <libsecret/secret.h>
#endif
#include "password-cache.h"
#include "memory.h"
#ifdef HAVE_LIBSECRET
static const SecretSchema *
gpg_schema (void)
{
static const SecretSchema the_schema = {
"org.gnupg.Passphrase", SECRET_SCHEMA_NONE,
{
{ "stored-by", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ "keygrip", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ "NULL", 0 },
}
};
return &the_schema;
}
static char *
keygrip_to_label (const char *keygrip)
{
char const prefix[] = "GnuPG: ";
char *label;
label = malloc (sizeof (prefix) + strlen (keygrip));
if (label)
{
memcpy (label, prefix, sizeof (prefix) - 1);
strcpy (&label[sizeof (prefix) - 1], keygrip);
}
return label;
}
#endif
void
password_cache_save (const char *keygrip, const char *password)
{
#ifdef HAVE_LIBSECRET
char *label;
GError *error = NULL;
if (! *keygrip)
return;
label = keygrip_to_label (keygrip);
if (! label)
return;
if (! secret_password_store_sync (gpg_schema (),
SECRET_COLLECTION_DEFAULT,
label, password, NULL, &error,
"stored-by", "GnuPG Pinentry",
"keygrip", keygrip, NULL))
{
printf("Failed to cache password for key %s with secret service: %s\n",
keygrip, error->message);
g_error_free (error);
}
free (label);
#else
return;
#endif
}
char *
password_cache_lookup (const char *keygrip)
{
#ifdef HAVE_LIBSECRET
GError *error = NULL;
char *password;
char *password2;
if (! *keygrip)
return NULL;
password = secret_password_lookup_nonpageable_sync
(gpg_schema (), NULL, &error,
"keygrip", keygrip, NULL);
if (error != NULL)
{
printf("Failed to lookup password for key %s with secret service: %s\n",
keygrip, error->message);
g_error_free (error);
return NULL;
}
if (! password)
/* The password for this key is not cached. Just return NULL. */
return NULL;
/* The password needs to be returned in secmem allocated memory. */
password2 = secmem_malloc (strlen (password) + 1);
if (password2)
strcpy(password2, password);
else
printf("secmem_malloc failed: can't copy password!\n");
secret_password_free (password);
return password2;
#else
return NULL;
#endif
}
/* Try and remove the cached password for key grip. Returns -1 on
error, 0 if the key is not found and 1 if the password was
removed. */
int
password_cache_clear (const char *keygrip)
{
#ifdef HAVE_LIBSECRET
GError *error = NULL;
int removed = secret_password_clear_sync (gpg_schema (), NULL, &error,
"keygrip", keygrip, NULL);
if (error != NULL)
{
printf("Failed to clear password for key %s with secret service: %s\n",
keygrip, error->message);
g_debug("%s", error->message);
g_error_free (error);
return -1;
}
if (removed)
return 1;
return 0;
#else
return -1;
#endif
}

29
pinentry/password-cache.h Normal file
View File

@ -0,0 +1,29 @@
/* password-cache.h - Password cache support interfaces.
Copyright (C) 2015 g10 Code GmbH
This file is part of PINENTRY.
PINENTRY 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.
PINENTRY 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef PASSWORD_CACHE_H
#define PASSWORD_CACHE_H
void password_cache_save (const char *key_grip, const char *password);
char *password_cache_lookup (const char *key_grip);
int password_cache_clear (const char *keygrip);
#endif

1308
pinentry/pinentry.c Normal file

File diff suppressed because it is too large Load Diff

280
pinentry/pinentry.h Normal file
View File

@ -0,0 +1,280 @@
/* pinentry.h - The interface for the PIN entry support library.
Copyright (C) 2002, 2003, 2010, 2015 g10 Code GmbH
This file is part of PINENTRY.
PINENTRY 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.
PINENTRY 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef PINENTRY_H
#define PINENTRY_H
#ifdef __cplusplus
extern "C" {
#if 0
}
#endif
#endif
typedef enum {
PINENTRY_COLOR_NONE, PINENTRY_COLOR_DEFAULT,
PINENTRY_COLOR_BLACK, PINENTRY_COLOR_RED,
PINENTRY_COLOR_GREEN, PINENTRY_COLOR_YELLOW,
PINENTRY_COLOR_BLUE, PINENTRY_COLOR_MAGENTA,
PINENTRY_COLOR_CYAN, PINENTRY_COLOR_WHITE
} pinentry_color_t;
struct pinentry
{
/* The window title, or NULL. (Assuan: "SETTITLE TITLE".) */
char *title;
/* The description to display, or NULL. (Assuan: "SETDESC
DESC".) */
char *description;
/* The error message to display, or NULL. (Assuan: "SETERROR
MESSAGE".) */
char *error;
/* The prompt to display, or NULL. (Assuan: "SETPROMPT
prompt".) */
char *prompt;
/* The OK button text to display, or NULL. (Assuan: "SETOK
OK".) */
char *ok;
/* The Not-OK button text to display, or NULL. This is the text for
the alternative option shown by the third button. (Assuan:
"SETNOTOK NOTOK".) */
char *notok;
/* The Cancel button text to display, or NULL. (Assuan: "SETCANCEL
CANCEL".) */
char *cancel;
/* The buffer to store the secret into. */
char *pin;
/* The length of the buffer. */
int pin_len;
/* Whether the pin was read from an external cache (1) or entered by
the user (0). */
int pin_from_cache;
/* The name of the X display to use if X is available and supported.
(Assuan: "OPTION display DISPLAY".) */
char *display;
/* The name of the terminal node to open if X not available or
supported. (Assuan: "OPTION ttyname TTYNAME".) */
char *ttyname;
/* The type of the terminal. (Assuan: "OPTION ttytype TTYTYPE".) */
char *ttytype;
/* The LC_CTYPE value for the terminal. (Assuan: "OPTION lc-ctype
LC_CTYPE".) */
char *lc_ctype;
/* The LC_MESSAGES value for the terminal. (Assuan: "OPTION
lc-messages LC_MESSAGES".) */
char *lc_messages;
/* True if debug mode is requested. */
int debug;
/* The number of seconds before giving up while waiting for user input. */
int timeout;
/* True if caller should grab the keyboard. (Assuan: "OPTION grab"
or "OPTION no-grab".) */
int grab;
/* The window ID of the parent window over which the pinentry window
should be displayed. (Assuan: "OPTION parent-wid WID".) */
int parent_wid;
/* The name of an optional file which will be touched after a curses
entry has been displayed. (Assuan: "OPTION touch-file
FILENAME".) */
char *touch_file;
/* The frontend should set this to -1 if the user canceled the
request, and to the length of the PIN stored in pin
otherwise. */
int result;
/* The frontend should set this if the NOTOK button was pressed. */
int canceled;
/* The frontend should set this to true if an error with the local
conversion occured. */
int locale_err;
/* The frontend should set this to a gpg-error so that commands are
able to return specific error codes. This is an ugly hack due to
the fact that pinentry_cmd_handler_t returns the length of the
passphrase or a negative error code. */
int specific_err;
/* The frontend should set this to true if the window close button
has been used. This flag is used in addition to a regular return
value. */
int close_button;
/* The caller should set this to true if only one button is
required. This is useful for notification dialogs where only a
dismiss button is required. */
int one_button;
/* If true a second prompt for the passphrase is shown and the user
is expected to enter the same passphrase again. Pinentry checks
that both match. (Assuan: "SETREPEAT".) */
char *repeat_passphrase;
/* The string to show if a repeated passphrase does not match.
(Assuan: "SETREPEATERROR ERROR".) */
char *repeat_error_string;
/* Set to true if the passphrase has been entered a second time and
matches the first passphrase. */
int repeat_okay;
/* If this is not NULL, a passphrase quality indicator is shown.
There will also be an inquiry back to the caller to get an
indication of the quality for the passphrase entered so far. The
string is used as a label for the quality bar. (Assuan:
"SETQUALITYBAR LABEL".) */
char *quality_bar;
/* The tooltip to be show for the qualitybar. Malloced or NULL.
(Assuan: "SETQUALITYBAR_TT TOOLTIP".) */
char *quality_bar_tt;
/* For the curses pinentry, the color of error messages. */
pinentry_color_t color_fg;
int color_fg_bright;
pinentry_color_t color_bg;
pinentry_color_t color_so;
int color_so_bright;
/* Malloced and i18ned default strings or NULL. These strings may
include an underscore character to indicate an accelerator key.
A double underscore represents a plain one. */
/* (Assuan: "OPTION default-ok OK"). */
char *default_ok;
/* (Assuan: "OPTION default-cancel CANCEL"). */
char *default_cancel;
/* (Assuan: "OPTION default-prompt PROMPT"). */
char *default_prompt;
/* (Assuan: "OPTION default-pwmngr
SAVE_PASSWORD_WITH_PASSWORD_MANAGER?"). */
char *default_pwmngr;
/* Whether we are allowed to read the password from an external
cache. (Assuan: "OPTION allow-external-password-cache") */
int allow_external_password_cache;
/* We only try the cache once. */
int tried_password_cache;
/* A stable identifier for the key. (Assuan: "SETKEYINFO
KEYINFO".) */
char *keyinfo;
/* Whether we may cache the password (according to the user). */
int may_cache_password;
/* NOTE: If you add any additional fields to this structure, be sure
to update the initializer in pinentry/pinentry.c!!! */
/* For the quality indicator we need to do an inquiry. Thus we need
to save the assuan ctx. */
void *ctx_assuan;
};
typedef struct pinentry *pinentry_t;
/* The pinentry command handler type processes the pinentry request
PIN. If PIN->pin is zero, request a confirmation, otherwise a PIN
entry. On confirmation, the function should return TRUE if
confirmed, and FALSE otherwise. On PIN entry, the function should
return -1 if an error occured or the user cancelled the operation
and 1 otherwise. */
typedef int (*pinentry_cmd_handler_t) (pinentry_t pin);
/* Start the pinentry event loop. The program will start to process
Assuan commands until it is finished or an error occurs. If an
error occurs, -1 is returned and errno indicates the type of an
error. Otherwise, 0 is returned. */
int pinentry_loop (void);
/* The same as above but allows to specify the i/o descriptors.
* infd and outfd will be duplicated in this function so the caller
* still has to close them if necessary.
*/
int pinentry_loop2 (int infd, int outfd);
/* Convert the UTF-8 encoded string TEXT to the encoding given in
LC_CTYPE. Return NULL on error. */
char *pinentry_utf8_to_local (const char *lc_ctype, const char *text);
/* Convert TEXT which is encoded according to LC_CTYPE to UTF-8. With
SECURE set to true, use secure memory for the returned buffer.
Return NULL on error. */
char *pinentry_local_to_utf8 (char *lc_ctype, char *text, int secure);
/* Run a quality inquiry for PASSPHRASE of LENGTH. */
int pinentry_inq_quality (pinentry_t pin,
const char *passphrase, size_t length);
/* Try to make room for at least LEN bytes for the pin in the pinentry
PIN. Returns new buffer on success and 0 on failure. */
char *pinentry_setbufferlen (pinentry_t pin, int len);
/* Use the buffer at BUFFER for PIN->PIN. BUFFER must be NULL or
allocated using secmem_alloc. LEN is the size of the buffer. If
it is unknown, but BUFFER is a NUL terminated string, you pass 0 to
just use strlen(buffer)+1. */
void pinentry_setbuffer_use (pinentry_t pin, char *buffer, int len);
/* Initialize the secure memory subsystem, drop privileges and
return. Must be called early. */
void pinentry_init (const char *pgmname);
/* Return true if either DISPLAY is set or ARGV contains the string
"--display". */
int pinentry_have_display (int argc, char **argv);
/* Parse the command line options. May exit the program if only help
or version output is requested. */
void pinentry_parse_opts (int argc, char *argv[]);
/* The caller must define this variable to process assuan commands. */
extern pinentry_cmd_handler_t pinentry_cmd_handler;
#ifdef HAVE_W32_SYSTEM
/* Windows declares sleep as obsolete, but provides a definition for
_sleep but non for the still existing sleep. */
#define sleep(a) _sleep ((a))
#endif /*HAVE_W32_SYSTEM*/
#if 0
{
#endif
#ifdef __cplusplus
}
#endif
#endif /* PINENTRY_H */

91
pinentry/secmem++.h Normal file
View File

@ -0,0 +1,91 @@
/* STL allocator for secmem
* Copyright (C) 2008 Marc Mutz <marc@kdab.com>
*
* This program 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.
*
* This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __SECMEM_SECMEMPP_H__
#define __SECMEM_SECMEMPP_H__
#include "secmem/memory.h"
#include <cstddef>
namespace secmem {
template <typename T>
class alloc {
public:
// type definitions:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
// rebind
template <typename U>
struct rebind {
typedef alloc<U> other;
};
// address
pointer address( reference value ) const {
return &value;
}
const_pointer address( const_reference value ) const {
return &value;
}
// (trivial) ctors and dtors
alloc() {}
alloc( const alloc & ) {}
template <typename U> alloc( const alloc<U> & ) {}
// copy ctor is ok
~alloc() {}
// de/allocation
size_type max_size() const {
return secmem_get_max_size();
}
pointer allocate( size_type n, void * =0 ) {
return static_cast<pointer>( secmem_malloc( n * sizeof(T) ) );
}
void deallocate( pointer p, size_type ) {
secmem_free( p );
}
// de/construct
void construct( pointer p, const T & value ) {
void * loc = p;
new (loc)T(value);
}
void destruct( pointer p ) {
p->~T();
}
};
// equality comparison
template <typename T1,typename T2>
bool operator==( const alloc<T1> &, const alloc<T2> & ) { return true; }
template <typename T1, typename T2>
bool operator!=( const alloc<T1> &, const alloc<T2> & ) { return false; }
}
#endif /* __SECMEM_SECMEMPP_H__ */

3
pinentry/secmem-util.h Normal file
View File

@ -0,0 +1,3 @@
/* This file exists because "util.h" is such a generic name that it is
likely to clash with other such files. */
#include "util.h"

460
pinentry/secmem.c Normal file
View File

@ -0,0 +1,460 @@
/* secmem.c - memory allocation from a secure heap
* Copyright (C) 1998, 1999, 2003 Free Software Foundation, Inc.
* Copyright (C) 2015 g10 Code GmbH
*
* 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 <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
# include <sys/mman.h>
# include <sys/types.h>
# include <fcntl.h>
# ifdef USE_CAPABILITIES
# include <sys/capability.h>
# endif
#endif
#include <string.h>
#include "memory.h"
#ifdef ORIGINAL_GPG_VERSION
#include "types.h"
#include "util.h"
#else /* ORIGINAL_GPG_VERSION */
#include "util.h"
typedef union {
int a;
short b;
char c[1];
long d;
#ifdef HAVE_U64_TYPEDEF
u64 e;
#endif
float f;
double g;
} PROPERLY_ALIGNED_TYPE;
#define log_error log_info
#define log_bug log_fatal
void
log_info(char *template, ...)
{
va_list args;
va_start(args, template);
vfprintf(stderr, template, args);
va_end(args);
}
void
log_fatal(char *template, ...)
{
va_list args;
va_start(args, template);
vfprintf(stderr, template, args);
va_end(args);
exit(EXIT_FAILURE);
}
#endif /* ORIGINAL_GPG_VERSION */
#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
# define MAP_ANONYMOUS MAP_ANON
#endif
#define DEFAULT_POOLSIZE 16384
typedef struct memblock_struct MEMBLOCK;
struct memblock_struct {
unsigned size;
union {
MEMBLOCK *next;
PROPERLY_ALIGNED_TYPE aligned;
} u;
};
static void *pool;
static volatile int pool_okay; /* may be checked in an atexit function */
static int pool_is_mmapped;
static size_t poolsize; /* allocated length */
static size_t poollen; /* used length */
static MEMBLOCK *unused_blocks;
static unsigned max_alloced;
static unsigned cur_alloced;
static unsigned max_blocks;
static unsigned cur_blocks;
static int disable_secmem;
static int show_warning;
static int no_warning;
static int suspend_warning;
static void
print_warn(void)
{
if( !no_warning )
log_info("Warning: using insecure memory!\n");
}
static void
lock_pool( void *p, size_t n )
{
#if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
int err;
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
err = mlock( p, n );
if( err && errno )
err = errno;
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
if( err ) {
if( errno != EPERM
#ifdef EAGAIN /* OpenBSD returns this */
&& errno != EAGAIN
#endif
)
log_error("can't lock memory: %s\n", strerror(err));
show_warning = 1;
}
#elif defined(HAVE_MLOCK)
uid_t uid;
int err;
uid = getuid();
#ifdef HAVE_BROKEN_MLOCK
if( uid ) {
errno = EPERM;
err = errno;
}
else {
err = mlock( p, n );
if( err && errno )
err = errno;
}
#else
err = mlock( p, n );
if( err && errno )
err = errno;
#endif
if( uid && !geteuid() ) {
if( setuid( uid ) || getuid() != geteuid() )
log_fatal("failed to reset uid: %s\n", strerror(errno));
}
if( err ) {
if( errno != EPERM
#ifdef EAGAIN /* OpenBSD returns this */
&& errno != EAGAIN
#endif
)
log_error("can't lock memory: %s\n", strerror(err));
show_warning = 1;
}
#else
log_info("Please note that you don't have secure memory on this system\n");
#endif
}
static void
init_pool( size_t n)
{
size_t pgsize;
poolsize = n;
if( disable_secmem )
log_bug("secure memory is disabled");
#ifdef HAVE_GETPAGESIZE
pgsize = getpagesize();
#else
pgsize = 4096;
#endif
#if HAVE_MMAP
poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
# ifdef MAP_ANONYMOUS
pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
# else /* map /dev/zero instead */
{ int fd;
fd = open("/dev/zero", O_RDWR);
if( fd == -1 ) {
log_error("can't open /dev/zero: %s\n", strerror(errno) );
pool = (void*)-1;
}
else {
pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
MAP_PRIVATE, fd, 0);
close (fd);
}
}
# endif
if( pool == (void*)-1 )
log_info("can't mmap pool of %u bytes: %s - using malloc\n",
(unsigned)poolsize, strerror(errno));
else {
pool_is_mmapped = 1;
pool_okay = 1;
}
#endif
if( !pool_okay ) {
pool = malloc( poolsize );
if( !pool )
log_fatal("can't allocate memory pool of %u bytes\n",
(unsigned)poolsize);
else
pool_okay = 1;
}
lock_pool( pool, poolsize );
poollen = 0;
}
/* concatenate unused blocks */
static void
compress_pool(void)
{
/* fixme: we really should do this */
}
void
secmem_set_flags( unsigned flags )
{
int was_susp = suspend_warning;
no_warning = flags & 1;
suspend_warning = flags & 2;
/* and now issue the warning if it is not longer suspended */
if( was_susp && !suspend_warning && show_warning ) {
show_warning = 0;
print_warn();
}
}
unsigned
secmem_get_flags(void)
{
unsigned flags;
flags = no_warning ? 1:0;
flags |= suspend_warning ? 2:0;
return flags;
}
void
secmem_init( size_t n )
{
if( !n ) {
#ifdef USE_CAPABILITIES
/* drop all capabilities */
cap_set_proc( cap_from_text("all-eip") );
#elif !defined(HAVE_DOSISH_SYSTEM)
uid_t uid;
disable_secmem=1;
uid = getuid();
if( uid != geteuid() ) {
if( setuid( uid ) || getuid() != geteuid() )
log_fatal("failed to drop setuid\n" );
}
#endif
}
else {
if( n < DEFAULT_POOLSIZE )
n = DEFAULT_POOLSIZE;
if( !pool_okay )
init_pool(n);
else
log_error("Oops, secure memory pool already initialized\n");
}
}
void *
secmem_malloc( size_t size )
{
MEMBLOCK *mb, *mb2;
int compressed=0;
if( !pool_okay ) {
log_info(
"operation is not possible without initialized secure memory\n");
log_info("(you may have used the wrong program for this task)\n");
exit(2);
}
if( show_warning && !suspend_warning ) {
show_warning = 0;
print_warn();
}
/* blocks are always a multiple of 32 */
size += sizeof(MEMBLOCK);
size = ((size + 31) / 32) * 32;
retry:
/* try to get it from the used blocks */
for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
if( mb->size >= size ) {
if( mb2 )
mb2->u.next = mb->u.next;
else
unused_blocks = mb->u.next;
goto leave;
}
/* allocate a new block */
if( (poollen + size <= poolsize) ) {
mb = (void*)((char*)pool + poollen);
poollen += size;
mb->size = size;
}
else if( !compressed ) {
compressed=1;
compress_pool();
goto retry;
}
else
return NULL;
leave:
cur_alloced += mb->size;
cur_blocks++;
if( cur_alloced > max_alloced )
max_alloced = cur_alloced;
if( cur_blocks > max_blocks )
max_blocks = cur_blocks;
memset (&mb->u.aligned.c, 0,
size - (size_t) &((struct memblock_struct *) 0)->u.aligned.c);
return &mb->u.aligned.c;
}
void *
secmem_realloc( void *p, size_t newsize )
{
MEMBLOCK *mb;
size_t size;
void *a;
if (! p)
return secmem_malloc(newsize);
mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
size = mb->size;
if( newsize < size )
return p; /* it is easier not to shrink the memory */
a = secmem_malloc( newsize );
memcpy(a, p, size);
memset((char*)a+size, 0, newsize-size);
secmem_free(p);
return a;
}
void
secmem_free( void *a )
{
MEMBLOCK *mb;
size_t size;
if( !a )
return;
mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
size = mb->size;
/* This does not make much sense: probably this memory is held in the
* cache. We do it anyway: */
wipememory2(mb, 0xff, size );
wipememory2(mb, 0xaa, size );
wipememory2(mb, 0x55, size );
wipememory2(mb, 0x00, size );
mb->size = size;
mb->u.next = unused_blocks;
unused_blocks = mb;
cur_blocks--;
cur_alloced -= size;
}
int
m_is_secure( const void *p )
{
return p >= pool && p < (void*)((char*)pool+poolsize);
}
void
secmem_term()
{
if( !pool_okay )
return;
wipememory2( pool, 0xff, poolsize);
wipememory2( pool, 0xaa, poolsize);
wipememory2( pool, 0x55, poolsize);
wipememory2( pool, 0x00, poolsize);
#if HAVE_MMAP
if( pool_is_mmapped )
munmap( pool, poolsize );
#endif
pool = NULL;
pool_okay = 0;
poolsize=0;
poollen=0;
unused_blocks=NULL;
}
void
secmem_dump_stats()
{
if( disable_secmem )
return;
fprintf(stderr,
"secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
cur_alloced, max_alloced, cur_blocks, max_blocks,
(ulong)poollen, (ulong)poolsize );
}
size_t
secmem_get_max_size (void)
{
return poolsize;
}

150
pinentry/util.c Normal file
View File

@ -0,0 +1,150 @@
/* Quintuple Agent
* Copyright (C) 1999 Robert Bihlmeyer <robbe@orcus.priv.at>
*
* This program 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.
*
* This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE 1
#include <unistd.h>
#ifndef HAVE_W32CE_SYSTEM
# include <errno.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#ifndef HAVE_DOSISH_SYSTEM
static int uid_set = 0;
static uid_t real_uid, file_uid;
#endif /*!HAVE_DOSISH_SYSTEM*/
/* Write DATA of size BYTES to FD, until all is written or an error
occurs. */
ssize_t
xwrite(int fd, const void *data, size_t bytes)
{
char *ptr;
size_t todo;
ssize_t written = 0;
for (ptr = (char *)data, todo = bytes; todo; ptr += written, todo -= written)
{
do
written = write (fd, ptr, todo);
while (
#ifdef HAVE_W32CE_SYSTEM
0
#else
written == -1 && errno == EINTR
#endif
);
if (written < 0)
break;
}
return written;
}
#if 0
extern int debug;
int
debugmsg(const char *fmt, ...)
{
va_list va;
int ret;
if (debug) {
va_start(va, fmt);
fprintf(stderr, "\e[4m");
ret = vfprintf(stderr, fmt, va);
fprintf(stderr, "\e[24m");
va_end(va);
return ret;
} else
return 0;
}
#endif
/* initialize uid variables */
#ifndef HAVE_DOSISH_SYSTEM
static void
init_uids(void)
{
real_uid = getuid();
file_uid = geteuid();
uid_set = 1;
}
#endif
#if 0 /* Not used. */
/* lower privileges to the real user's */
void
lower_privs()
{
if (!uid_set)
init_uids();
if (real_uid != file_uid) {
#ifdef HAVE_SETEUID
if (seteuid(real_uid) < 0) {
perror("lowering privileges failed");
exit(EXIT_FAILURE);
}
#else
fprintf(stderr, _("Warning: running q-agent setuid on this system is dangerous\n"));
#endif /* HAVE_SETEUID */
}
}
#endif /* if 0 */
#if 0 /* Not used. */
/* raise privileges to the effective user's */
void
raise_privs()
{
assert(real_uid >= 0); /* lower_privs() must be called before this */
#ifdef HAVE_SETEUID
if (real_uid != file_uid && seteuid(file_uid) < 0) {
perror("Warning: raising privileges failed");
}
#endif /* HAVE_SETEUID */
}
#endif /* if 0 */
/* drop all additional privileges */
void
drop_privs()
{
#ifndef HAVE_DOSISH_SYSTEM
if (!uid_set)
init_uids();
if (real_uid != file_uid) {
if (setuid(real_uid) < 0) {
perror("dropping privileges failed");
exit(EXIT_FAILURE);
}
file_uid = real_uid;
}
#endif
}

66
pinentry/util.h Normal file
View File

@ -0,0 +1,66 @@
/* Quintuple Agent utilities
* Copyright (C) 1999 Robert Bihlmeyer <robbe@orcus.priv.at>
* Copyright (C) 2003 g10 Code GmbH
*
* This program 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.
*
* This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _UTIL_H
#define _UTIL_H
#include <sys/types.h>
#ifndef HAVE_BYTE_TYPEDEF
# undef byte
# ifdef __riscos__
/* Norcroft treats char == unsigned char but char* != unsigned char* */
typedef char byte;
# else
typedef unsigned char byte;
# endif
# define HAVE_BYTE_TYPEDEF
#endif
#ifndef HAVE_ULONG_TYPEDEF
# undef ulong
typedef unsigned long ulong;
# define HAVE_ULONG_TYPEDEF
#endif
ssize_t xwrite(int, const void *, size_t); /* write until finished */
int debugmsg(const char *, ...); /* output a debug message if debugging==on */
void drop_privs(void); /* finally drop privileges */
/* To avoid that a compiler optimizes certain memset calls away, these
macros may be used instead. */
#define wipememory2(_ptr,_set,_len) do { \
volatile char *_vptr=(volatile char *)(_ptr); \
size_t _vlen=(_len); \
while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
} while(0)
#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
#define wipe(_ptr,_len) wipememory2(_ptr,0,_len)
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
#endif

43
test Executable file
View File

@ -0,0 +1,43 @@
#!/bin/sh
if [[ $1 -eq 1 ]]; then
echo "SETTITLE title
SETPROMPT prompt
SETDESC PROMPT
GETPIN
BYE" | ./pinentry-dmenu
elif [[ $1 -eq 2 ]]; then
echo "SETTITLE title
SETPROMPT confirm
SETDESC CONFIRM
confirm
BYE" | ./pinentry-dmenu
elif [[ $1 -eq 3 ]]; then
echo "SETTITLE title
SETPROMPT prompt
SETDESC REPEAT
SETREPEAT repeat
GETPIN
BYE" | ./pinentry-dmenu
else
echo "SETTITLE title
SETPROMPT prompt
SETDESC PROMPT
GETPIN
SETPROMPT confirm
SETDESC CONFIRM
confirm
SETPROMPT repeat
SETDESC REPEAT
SETREPEAT
GETPIN
BYE" | ./pinentry-dmenu
fi

35
util.c Normal file
View File

@ -0,0 +1,35 @@
/* See LICENSE file for copyright and license details. */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
void *
ecalloc(size_t nmemb, size_t size)
{
void *p;
if (!(p = calloc(nmemb, size)))
die("calloc:");
return p;
}
void
die(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
fputc(' ', stderr);
perror(NULL);
} else {
fputc('\n', stderr);
}
exit(1);
}

8
util.h Normal file
View File

@ -0,0 +1,8 @@
/* See LICENSE file for copyright and license details. */
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
void die(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size);