mirror of https://gitee.com/openkylin/stoken.git
Import Upstream version 0.92
This commit is contained in:
commit
590a4e56a1
|
@ -0,0 +1,41 @@
|
|||
# autotools stuff
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
configure
|
||||
install-sh
|
||||
src/.deps/
|
||||
src/.dirstamp
|
||||
src/*.lo
|
||||
src/.libs/
|
||||
stamp-h1
|
||||
autom4te.cache/
|
||||
.libs/
|
||||
*.la
|
||||
build-aux/
|
||||
libtool
|
||||
test-suite.log
|
||||
|
||||
# objects
|
||||
/src/*.o
|
||||
/stoken
|
||||
/stoken-gui
|
||||
/stoken-*.tar.gz
|
||||
/stoken.pc
|
||||
|
||||
# scratch files
|
||||
.*.sw*
|
||||
*~
|
||||
|
||||
# Debian
|
||||
ppa/changelog
|
||||
tmp.debian
|
||||
|
||||
# Windows
|
||||
winpkg/
|
||||
winpkg.zip
|
||||
*.exe
|
|
@ -0,0 +1,123 @@
|
|||
V0.92 - 2017/11/12
|
||||
|
||||
- Update MinGW dependencies to work with Fedora 25 (bug #31)
|
||||
|
||||
- Fix compatibility with libtomcrypt 1.18 (bug #38)
|
||||
|
||||
- Invoke locally-generated libtool binary instead of assuming there is
|
||||
one in the $PATH (bug #37)
|
||||
|
||||
- Use $USERPROFILE instead of $HOME on Windows 7 (bug #22)
|
||||
|
||||
V0.91 - 2017/01/08
|
||||
|
||||
- Fix segfault if ~/.stokenrc is empty and another program invokes libstoken
|
||||
|
||||
- Squash extraneous newline from `stoken tokencode` if stdin isn't a
|
||||
tty (bug #29)
|
||||
|
||||
V0.90 - 2015/08/09
|
||||
|
||||
- Change version number from v0.9 -> v0.90 to make life easier for packagers
|
||||
|
||||
V0.9 - 2015/07/25
|
||||
|
||||
- Fix corner case in SDTID reader (bug #21)
|
||||
|
||||
- Support Nettle 3.x (bug #20)
|
||||
|
||||
- Other minor fixes
|
||||
|
||||
V0.81 - 2014/12/08
|
||||
|
||||
- Fix "make check" failures in GMT+xx timezones (xx >= 1)
|
||||
|
||||
V0.8 - 2014/12/07
|
||||
|
||||
- Update GUI from GTK+2 to GTK+3; use glade to define the layouts
|
||||
|
||||
- Add next tokencode and other information to the full GUI (stoken-gui).
|
||||
The "stoken-gui --small" layout is unchanged.
|
||||
|
||||
- Add a list of known GUIDs used to bind tokens to specific device classes
|
||||
(i.e. tokens can be bound to "any BlackBerry 10"). stoken will now try
|
||||
each one of these IDs when importing a new bound token.
|
||||
|
||||
- Add new --qr and --show-qr export options to make it easy to pass tokens
|
||||
to a mobile device
|
||||
|
||||
- Add "stoken --next" option to show the next tokencode
|
||||
|
||||
- Support using nettle+gmp as an alternative to libtomcrypt
|
||||
|
||||
- Generate valid TKNTrailer BatchSignature sections in .sdtid output files,
|
||||
allowing use with RSA's official TokenConverter utility
|
||||
|
||||
- Fix parsing of RSA-supplied hard token seed files
|
||||
|
||||
- Add "make check" and several test cases
|
||||
|
||||
- Fix build errors on Mac OSX, enable OSX Travis builds, and submit a
|
||||
Homebrew formula
|
||||
|
||||
- Fix build errors when using uClibc instead of glibc
|
||||
|
||||
- Add experimental Windows build using MinGW (see README for instructions)
|
||||
|
||||
- Relicense the JNI wrapper (BSD-3-clause) so that it is easier to incorporate
|
||||
into non-free Android apps
|
||||
|
||||
- Various fixes for minor bugs, memory leaks, etc.
|
||||
|
||||
v0.6 - 2014/06/21
|
||||
|
||||
- Add support for reading and writing v3 (base64-encoded) Android tokens
|
||||
|
||||
- Add support for 30-second tokens. Library users should call
|
||||
stoken_get_info() to check the token interval.
|
||||
|
||||
- Add "stoken-gui --small" mode to conserve desktop space
|
||||
|
||||
- Enable Alt-C and Alt-Q keyboard shortcuts in stoken-gui
|
||||
|
||||
- Fix handling of cached PINs for library callers
|
||||
|
||||
- Fix JNI symbol exports
|
||||
|
||||
- Fix "stoken issue" if no token is imported
|
||||
|
||||
- Add new stoken_get_info() API to query the S/N and expiration date
|
||||
|
||||
- Minor documentation updates
|
||||
|
||||
v0.5 - 2014/03/15
|
||||
|
||||
- Add support for importing/exporting sdtid XML files. The library now
|
||||
depends on libxml.
|
||||
|
||||
- Add JNI code for integration into Android apps
|
||||
|
||||
- Add support for 6-digit tokencodes
|
||||
|
||||
- Fix problems decrypting some device-ID-bound tokens (bug #3)
|
||||
|
||||
- Fix build failures on kfreebsd and Android
|
||||
|
||||
- Fix handling of PIN-less tokens
|
||||
|
||||
- Fix out-of-tree builds
|
||||
|
||||
- Don't strip stoken / stoken-gui binaries by default
|
||||
|
||||
v0.2 - 2013/05/18
|
||||
|
||||
- Fix a couple of problems seen when manipulating tokens tied to a device
|
||||
ID, particularly if the token was intended for a smartphone (bug #1)
|
||||
|
||||
- Clean up pkg-config dependencies
|
||||
|
||||
- Other minor cleanups
|
||||
|
||||
v0.1 - 2012/11/17
|
||||
|
||||
- Initial public release
|
|
@ -0,0 +1,504 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
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 and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, 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 library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete 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 distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
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 Library or any portion
|
||||
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
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 Library, 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 Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you 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.
|
||||
|
||||
If distribution of 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 satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be 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.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library 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.
|
||||
|
||||
9. 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 Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
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 with
|
||||
this License.
|
||||
|
||||
11. 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 Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library 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 Library.
|
||||
|
||||
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.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library 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.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser 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 Library
|
||||
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 Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
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
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. 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 LIBRARY 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
|
||||
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
AUTOMAKE_OPTIONS = foreign subdir-objects
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SHELL = /bin/bash
|
||||
|
||||
AM_CPPFLAGS = -DDATA_DIR=\"$(datadir)\"
|
||||
AM_CFLAGS = $(CRYPTO_CFLAGS) $(LIBXML2_CFLAGS) $(WFLAGS)
|
||||
|
||||
dist_man_MANS = stoken.1
|
||||
|
||||
lib_LTLIBRARIES = libstoken.la
|
||||
libstoken_la_SOURCES = src/library.c src/securid.c src/sdtid.c \
|
||||
src/compat.c src/stc-@CRYPTO_BACKEND@.c
|
||||
libstoken_la_CFLAGS = $(AM_CFLAGS) -DLIBSTOKEN_BUILD
|
||||
|
||||
libstoken_la_LDFLAGS = -version-number @APIMAJOR@:@APIMINOR@ \
|
||||
-no-undefined
|
||||
if HAVE_VSCRIPT_COMPLEX
|
||||
libstoken_la_LDFLAGS += $(VSCRIPT_LDFLAGS),@srcdir@/libstoken.map
|
||||
endif
|
||||
|
||||
libstoken_la_LIBADD = $(CRYPTO_LIBS) $(LIBXML2_LIBS)
|
||||
libstoken_la_DEPENDENCIES = libstoken.map
|
||||
include_HEADERS = src/stoken.h
|
||||
noinst_HEADERS = src/common.h src/securid.h src/stoken-internal.h \
|
||||
src/sdtid.h
|
||||
pkgconfig_DATA = stoken.pc
|
||||
|
||||
if USE_JNI
|
||||
if JNI_STANDALONE
|
||||
libstoken_la_SOURCES += src/jni.c
|
||||
libstoken_la_CFLAGS += $(JNI_CFLAGS)
|
||||
else
|
||||
lib_LTLIBRARIES += libstoken-wrapper.la
|
||||
libstoken_wrapper_la_SOURCES = src/jni.c
|
||||
libstoken_wrapper_la_CFLAGS = $(AM_CFLAGS) $(JNI_CFLAGS)
|
||||
libstoken_wrapper_la_LIBADD = libstoken.la
|
||||
endif
|
||||
endif
|
||||
|
||||
bin_PROGRAMS = stoken
|
||||
stoken_SOURCES = src/cli.c src/common.c
|
||||
stoken_LDADD = $(LDADD) $(CRYPTO_LIBS) libstoken.la
|
||||
|
||||
if ENABLE_GUI
|
||||
bin_PROGRAMS += stoken-gui
|
||||
stoken_gui_SOURCES = src/gui.c src/common.c
|
||||
stoken_gui_CFLAGS = $(AM_CFLAGS) $(GTK_CFLAGS)
|
||||
stoken_gui_CPPFLAGS = $(AM_CPPFLAGS) -DUIDIR=\"$(uidir)\"
|
||||
stoken_gui_LDADD = $(LDADD) $(CRYPTO_LIBS) libstoken.la $(GTK_LIBS)
|
||||
|
||||
dist_man_MANS += stoken-gui.1
|
||||
|
||||
icondir = $(datadir)/pixmaps
|
||||
dist_icon_DATA = gui/stoken-gui.png
|
||||
|
||||
desktopdir = $(datadir)/applications
|
||||
dist_desktop_DATA = gui/stoken-gui.desktop \
|
||||
gui/stoken-gui-small.desktop
|
||||
|
||||
uidir = $(datadir)/stoken
|
||||
ui_DATA = gui/tokencode-small.ui \
|
||||
gui/tokencode-detail.ui \
|
||||
gui/password-dialog.ui \
|
||||
gui/pin-dialog.ui
|
||||
|
||||
endif
|
||||
|
||||
dist_doc_DATA = examples/libstoken-test.c examples/sdtid-test.pl \
|
||||
README.md
|
||||
|
||||
dist_noinst_SCRIPTS = autogen.sh
|
||||
|
||||
EXTRA_DIST = .gitignore libstoken.map CHANGES $(ui_DATA)
|
||||
|
||||
# package both variants explicitly, because @CRYPTO_BACKEND@ only picks one
|
||||
EXTRA_DIST += src/stc-nettle.c src/stc-tomcrypt.c
|
||||
|
||||
GIT_EXTRA_DIST = examples/ java/ tests/
|
||||
EXTRA_DIST += $(shell cd "$(top_srcdir)" && \
|
||||
git ls-tree HEAD -r --name-only -- $(GIT_EXTRA_DIST) 2>/dev/null)
|
||||
|
||||
TEST_EXTENSIONS = .pipe
|
||||
TESTS = tests/export-android-v2.pipe \
|
||||
tests/export-iphone-password.pipe \
|
||||
tests/export-read-v3.pipe \
|
||||
tests/export-sdtid-devid-password.pipe \
|
||||
tests/export-v3-sdtid.pipe \
|
||||
tests/tokencode-v2.pipe \
|
||||
tests/tokencode-v3.pipe \
|
||||
tests/tokencode-sdtid.pipe \
|
||||
tests/mac-align.pipe
|
||||
|
||||
PIPE_LOG_COMPILER = $(srcdir)/tests/pipe-wrapper.sh
|
||||
dist_check_SCRIPTS = $(TESTS) $(PIPE_LOG_COMPILER)
|
||||
|
||||
TESTS_ENVIRONMENT = STOKEN=./stoken \
|
||||
LIBTOOL="${LIBTOOL}" \
|
||||
TESTDIR="$(srcdir)/tests"
|
||||
|
||||
if ENABLE_VALGRIND
|
||||
TESTS_ENVIRONMENT += VALGRIND="valgrind --error-exitcode=1"
|
||||
endif
|
||||
|
||||
DISTCLEANFILES = *~
|
||||
|
||||
.PHONY: winpkg
|
||||
winpkg: $(bin_PROGRAMS)
|
||||
rm -rf winpkg
|
||||
mkdir winpkg
|
||||
cp .libs/stoken.exe winpkg/
|
||||
if ENABLE_GUI
|
||||
cp .libs/stoken-gui.exe winpkg/
|
||||
cp `./win32deps.pl .libs/stoken-gui.exe` winpkg/
|
||||
cp gui/*.{ui,png} winpkg/
|
||||
else
|
||||
cp .libs/stoken.exe winpkg/
|
||||
cp `./win32deps.pl .libs/stoken.exe` winpkg/
|
||||
endif
|
||||
rm -f winpkg.zip
|
||||
zip -r winpkg.zip winpkg/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,150 @@
|
|||
stoken - Software Token for Linux/UNIX
|
||||
======================================
|
||||
|
||||
stoken is a tokencode generator compatible with RSA SecurID 128-bit (AES)
|
||||
tokens. The project includes several components:
|
||||
|
||||
* A simple command line interface (CLI) used to manage and manipulate tokens
|
||||
* A GTK+ GUI with cut&paste functionality
|
||||
* A shared library allowing other software to generate tokencodes on demand
|
||||
|
||||
## Building on Linux
|
||||
|
||||
### Dependencies
|
||||
|
||||
* libtomcrypt or nettle
|
||||
* libxml2
|
||||
* libgtk3.0 (required for stoken-gui only)
|
||||
|
||||
If you are building from Git, you'll need to install autoconf / automake /
|
||||
libtool, and run autogen.sh first. This is not necessary if building from
|
||||
a released source tarball.
|
||||
|
||||
On Debian or Ubuntu, this should satisfy most/all dependencies:
|
||||
|
||||
sudo apt-get install libgtk-3-dev libtomcrypt-dev libxml2-dev libtomcrypt-dev autoconf automake libtool build-essential
|
||||
|
||||
### Compile instructions
|
||||
|
||||
./configure
|
||||
make
|
||||
make check
|
||||
make install
|
||||
|
||||
## Usage
|
||||
|
||||
First, import a token from a raw string or an "sdtid" XML file:
|
||||
|
||||
stoken import --token 2000123456...
|
||||
stoken import --token com.rsa.securid.iphone://ctf?ctfData=2000123456...
|
||||
stoken import --file mytoken.sdtid
|
||||
|
||||
This will prompt for an optional password, so that your seed is encrypted
|
||||
on disk.
|
||||
|
||||
Next, use the CLI or GUI to show the current tokencode:
|
||||
|
||||
stoken tokencode
|
||||
stoken-gui &
|
||||
|
||||
If your token requires a PIN, stoken will prompt for it. You can use
|
||||
<code>stoken setpin</code> to cache your PIN in <code>~/.stokenrc</code>.
|
||||
This is much less secure, but may be useful for automation.
|
||||
|
||||
Modern versions of OpenConnect link against libstoken and can send an
|
||||
autogenerated tokencode as the password. Import your token using the
|
||||
above instructions, then:
|
||||
|
||||
openconnect -u USERNAME --token-mode=rsa HOSTNAME
|
||||
|
||||
See the man pages for additional details: stoken(1), stoken-gui(1)
|
||||
|
||||
See examples/ and src/stoken.h for information on using the shared library
|
||||
interface (libstoken) to generate tokencodes from other applications.
|
||||
|
||||
## Screenshots
|
||||
|
||||
<table border=1 cellpadding=15>
|
||||
<tr align="center">
|
||||
<td><code>stoken-gui</code>
|
||||
<td><code>stoken-gui --small</code>
|
||||
<tr valign="top">
|
||||
<td><img src="misc/screenshot-0.png">
|
||||
<td><img src="misc/screenshot-1.png">
|
||||
</table>
|
||||
|
||||
## Building on other platforms
|
||||
|
||||
### Mac OS X
|
||||
|
||||
#### Initial setup
|
||||
|
||||
The following configuration was tested under Mavericks 10.9.5; other
|
||||
variants may work too:
|
||||
|
||||
* Install gcc/make/headers: <code>xcode-select --install</code>
|
||||
* Install [Homebrew](http://brew.sh/)
|
||||
* Install [XQuartz](http://xquartz.macosforge.org/) to support GTK+3
|
||||
* Use Homebrew to satisfy dependencies: <code>brew install git autoconf
|
||||
automake libtool nettle pkg-config gtk+3 gnome-icon-theme
|
||||
hicolor-icon-theme</code>
|
||||
* Use OSX's builtin libxml2 (no action needed)
|
||||
|
||||
#### Compiling
|
||||
|
||||
Note that GNU libtool is called <code>glibtool</code> to avoid collisions
|
||||
with Apple's libtool program:
|
||||
|
||||
export LIBTOOL=glibtool
|
||||
git clone git://github.com/cernekee/stoken
|
||||
cd stoken
|
||||
bash autogen.sh
|
||||
./configure
|
||||
make
|
||||
make check
|
||||
make install
|
||||
|
||||
### Experimental Windows build
|
||||
|
||||
As of v0.8, stoken can be built for Windows using the [MinGW cross toolchain
|
||||
on Fedora](http://fedoraproject.org/wiki/MinGW). This is not tested
|
||||
or maintained regularly.
|
||||
|
||||
#### Initial setup
|
||||
|
||||
On a Fedora 20 PC (other versions may work as well), install the build
|
||||
dependencies:
|
||||
|
||||
yum groupinstall "Development Tools"
|
||||
yum install git autoconf automake libtool mingw32-gnutls mingw32-libxml2 mingw32-gtk3
|
||||
|
||||
#### Compiling
|
||||
|
||||
git clone git://github.com/cernekee/stoken
|
||||
cd stoken
|
||||
bash autogen.sh
|
||||
mingw32-configure
|
||||
make winpkg
|
||||
|
||||
If all goes well, you should be able to copy <code>winpkg.zip</code> to
|
||||
a Windows PC and run <code>stoken.exe</code> or <code>stoken-gui.exe</code>.
|
||||
|
||||
#### TODO
|
||||
|
||||
Several items are known to be missing or broken on the Windows build:
|
||||
|
||||
* Default home directory is probably incorrect
|
||||
* No installer
|
||||
* The GUI requires its assets to be in the current directory
|
||||
* Password entry is not masked
|
||||
* <code>stoken --random</code> flag
|
||||
* No charset translation on filenames
|
||||
|
||||
## Misc
|
||||
|
||||
Author: Kevin Cernekee <cernekee@gmail.com>
|
||||
|
||||
License: LGPLv2.1+
|
||||
|
||||
stoken is a hobbyist project, not affiliated with or endorsed by
|
||||
RSA Security.
|
|
@ -0,0 +1,13 @@
|
|||
TODO list:
|
||||
|
||||
Library functions probably need man pages.
|
||||
|
||||
Consider sanitizing memory, and figure out how to avoid leaking key material.
|
||||
|
||||
Fix alpha channel on the icon.
|
||||
|
||||
Make better use of the public library functions from cli/gui.
|
||||
|
||||
vpnc integration.
|
||||
|
||||
Add hotkeys, import/about dialogs, other features to the GUI.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
autoreconf --force --install --verbose
|
||||
rm -rf autom4te*.cache
|
|
@ -0,0 +1,347 @@
|
|||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2012-10-14.11; # UTC
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.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, 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,791 @@
|
|||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2013-05-30.07; # UTC
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
|
||||
# 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, 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Get the directory component of the given path, and save it in the
|
||||
# global variables '$dir'. Note that this directory component will
|
||||
# be either empty or ending with a '/' character. This is deliberate.
|
||||
set_dir_from ()
|
||||
{
|
||||
case $1 in
|
||||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
|
||||
*) dir=;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the suffix-stripped basename of the given path, and save it the
|
||||
# global variable '$base'.
|
||||
set_base_from ()
|
||||
{
|
||||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
|
||||
}
|
||||
|
||||
# If no dependency file was actually created by the compiler invocation,
|
||||
# we still have to create a dummy depfile, to avoid errors with the
|
||||
# Makefile "include basename.Plo" scheme.
|
||||
make_dummy_depfile ()
|
||||
{
|
||||
echo "#dummy" > "$depfile"
|
||||
}
|
||||
|
||||
# Factor out some common post-processing of the generated depfile.
|
||||
# Requires the auxiliary global variable '$tmpdepfile' to be set.
|
||||
aix_post_process_depfile ()
|
||||
{
|
||||
# If the compiler actually managed to produce a dependency file,
|
||||
# post-process it.
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form 'foo.o: dependency.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# $object: dependency.h
|
||||
# and one to simply output
|
||||
# dependency.h:
|
||||
# which is needed to avoid the deleted-header problem.
|
||||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
|
||||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
|
||||
} > "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
}
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
# Character ranges might be problematic outside the C locale.
|
||||
# These definitions help.
|
||||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
lower=abcdefghijklmnopqrstuvwxyz
|
||||
digits=0123456789
|
||||
alpha=${upper}${lower}
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Avoid interferences from the environment.
|
||||
gccflag= dashmflag=
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
|
||||
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
|
||||
## (see the conditional assignment to $gccflag above).
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say). Also, it might not be
|
||||
## supported by the other compilers which use the 'gcc' depmode.
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The second -e expression handles DOS-style file names with drive
|
||||
# letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
|
||||
| tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
tcc)
|
||||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
|
||||
# FIXME: That version still under development at the moment of writing.
|
||||
# Make that this statement remains true also for stable, released
|
||||
# versions.
|
||||
# It will wrap lines (doesn't matter whether long or short) with a
|
||||
# trailing '\', as in:
|
||||
#
|
||||
# foo.o : \
|
||||
# foo.c \
|
||||
# foo.h \
|
||||
#
|
||||
# It will put a trailing '\' even on the last line, and will use leading
|
||||
# spaces rather than leading tabs (at least since its commit 0394caf7
|
||||
# "Emit spaces for -MD").
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
|
||||
# We have to change lines of the first kind to '$object: \'.
|
||||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
|
||||
# And for each line of the second kind, we have to emit a 'dep.h:'
|
||||
# dummy dependency, to avoid the deleted-header problem.
|
||||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
## The order of this option in the case statement is important, since the
|
||||
## shell code in configure will try each of these formats in the order
|
||||
## listed in this file. A plain '-MD' option would be understood by many
|
||||
## compilers, so we must ensure this comes after the gcc and icc options.
|
||||
pgcc)
|
||||
# Portland's C compiler understands '-MD'.
|
||||
# Will always output deps to 'file.d' where file is the root name of the
|
||||
# source file under compilation, even if file resides in a subdirectory.
|
||||
# The object file name does not affect the name of the '.d' file.
|
||||
# pgcc 10.2 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using '\' :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
set_dir_from "$object"
|
||||
# Use the source, not the object, to determine the base name, since
|
||||
# that's sadly what pgcc will do too.
|
||||
set_base_from "$source"
|
||||
tmpdepfile=$base.d
|
||||
|
||||
# For projects that build the same source file twice into different object
|
||||
# files, the pgcc approach of using the *source* file root name can cause
|
||||
# problems in parallel builds. Use a locking strategy to avoid stomping on
|
||||
# the same $tmpdepfile.
|
||||
lockdir=$base.d-lock
|
||||
trap "
|
||||
echo '$0: caught signal, cleaning up...' >&2
|
||||
rmdir '$lockdir'
|
||||
exit 1
|
||||
" 1 2 13 15
|
||||
numtries=100
|
||||
i=$numtries
|
||||
while test $i -gt 0; do
|
||||
# mkdir is a portable test-and-set.
|
||||
if mkdir "$lockdir" 2>/dev/null; then
|
||||
# This process acquired the lock.
|
||||
"$@" -MD
|
||||
stat=$?
|
||||
# Release the lock.
|
||||
rmdir "$lockdir"
|
||||
break
|
||||
else
|
||||
# If the lock is being held by a different process, wait
|
||||
# until the winning process is done or we timeout.
|
||||
while test -d "$lockdir" && test $i -gt 0; do
|
||||
sleep 1
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
fi
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
trap - 1 2 13 15
|
||||
if test $i -le 0; then
|
||||
echo "$0: failed to acquire lock after $numtries attempts" >&2
|
||||
echo "$0: check lockdir '$lockdir'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# Libtool generates 2 separate objects for the 2 libraries. These
|
||||
# two compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
|
||||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
# Same post-processing that is required for AIX mode.
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this sed invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process the last invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed '1,2d' "$tmpdepfile" \
|
||||
| tr ' ' "$nl" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E \
|
||||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
| sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,508 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2014-09-12.12; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
# $RANDOM is not portable (e.g. dash); use it when possible to
|
||||
# lower collision chance
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
# As "mkdir -p" follows symlinks and we work in /tmp possibly; so
|
||||
# create the $tmpdir first (and fail if unsuccessful) to make sure
|
||||
# that nobody tries to guess the $tmpdir name.
|
||||
if (umask $mkdir_umask &&
|
||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
test_tmpdir="$tmpdir/a"
|
||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,215 @@
|
|||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU programs.
|
||||
|
||||
scriptversion=2013-10-28.13; # UTC
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# 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, 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autoheader autom4te automake makeinfo
|
||||
bison yacc flex lex help2man
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=http://www.perl.org/
|
||||
flex_URL=http://flex.sourceforge.net/
|
||||
gnu_software_URL=http://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
case $normalized_program in
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified 'configure.ac',"
|
||||
echo "or m4 files included by it."
|
||||
program_details 'autoconf'
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified 'acconfig.h' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'autoheader'
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified 'Makefile.am' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'automake'
|
||||
;;
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified 'acinclude.m4' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'aclocal'
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
program_details 'autom4te'
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,148 @@
|
|||
#! /bin/sh
|
||||
# test-driver - basic testsuite driver script.
|
||||
|
||||
scriptversion=2013-07-13.22; # UTC
|
||||
|
||||
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
|
||||
#
|
||||
# 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, 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
# Make unconditional expansion of undefined variables an error. This
|
||||
# helps a lot in preventing typo-related bugs.
|
||||
set -u
|
||||
|
||||
usage_error ()
|
||||
{
|
||||
echo "$0: $*" >&2
|
||||
print_usage >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
print_usage ()
|
||||
{
|
||||
cat <<END
|
||||
Usage:
|
||||
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
|
||||
[--expect-failure={yes|no}] [--color-tests={yes|no}]
|
||||
[--enable-hard-errors={yes|no}] [--]
|
||||
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
|
||||
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
|
||||
END
|
||||
}
|
||||
|
||||
test_name= # Used for reporting.
|
||||
log_file= # Where to save the output of the test script.
|
||||
trs_file= # Where to save the metadata of the test run.
|
||||
expect_failure=no
|
||||
color_tests=no
|
||||
enable_hard_errors=yes
|
||||
while test $# -gt 0; do
|
||||
case $1 in
|
||||
--help) print_usage; exit $?;;
|
||||
--version) echo "test-driver $scriptversion"; exit $?;;
|
||||
--test-name) test_name=$2; shift;;
|
||||
--log-file) log_file=$2; shift;;
|
||||
--trs-file) trs_file=$2; shift;;
|
||||
--color-tests) color_tests=$2; shift;;
|
||||
--expect-failure) expect_failure=$2; shift;;
|
||||
--enable-hard-errors) enable_hard_errors=$2; shift;;
|
||||
--) shift; break;;
|
||||
-*) usage_error "invalid option: '$1'";;
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
missing_opts=
|
||||
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
|
||||
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
|
||||
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
|
||||
if test x"$missing_opts" != x; then
|
||||
usage_error "the following mandatory options are missing:$missing_opts"
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
usage_error "missing argument"
|
||||
fi
|
||||
|
||||
if test $color_tests = yes; then
|
||||
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
|
||||
red='[0;31m' # Red.
|
||||
grn='[0;32m' # Green.
|
||||
lgn='[1;32m' # Light green.
|
||||
blu='[1;34m' # Blue.
|
||||
mgn='[0;35m' # Magenta.
|
||||
std='[m' # No color.
|
||||
else
|
||||
red= grn= lgn= blu= mgn= std=
|
||||
fi
|
||||
|
||||
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
|
||||
trap "st=129; $do_exit" 1
|
||||
trap "st=130; $do_exit" 2
|
||||
trap "st=141; $do_exit" 13
|
||||
trap "st=143; $do_exit" 15
|
||||
|
||||
# Test script is run here.
|
||||
"$@" >$log_file 2>&1
|
||||
estatus=$?
|
||||
|
||||
if test $enable_hard_errors = no && test $estatus -eq 99; then
|
||||
tweaked_estatus=1
|
||||
else
|
||||
tweaked_estatus=$estatus
|
||||
fi
|
||||
|
||||
case $tweaked_estatus:$expect_failure in
|
||||
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
|
||||
0:*) col=$grn res=PASS recheck=no gcopy=no;;
|
||||
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
|
||||
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
|
||||
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
|
||||
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
|
||||
esac
|
||||
|
||||
# Report the test outcome and exit status in the logs, so that one can
|
||||
# know whether the test passed or failed simply by looking at the '.log'
|
||||
# file, without the need of also peaking into the corresponding '.trs'
|
||||
# file (automake bug#11814).
|
||||
echo "$res $test_name (exit status: $estatus)" >>$log_file
|
||||
|
||||
# Report outcome to console.
|
||||
echo "${col}${res}${std}: $test_name"
|
||||
|
||||
# Register the test result, and other relevant metadata.
|
||||
echo ":test-result: $res" > $trs_file
|
||||
echo ":global-test-result: $res" >> $trs_file
|
||||
echo ":recheck: $recheck" >> $trs_file
|
||||
echo ":copy-in-global-log: $gcopy" >> $trs_file
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,117 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the `asprintf' function. */
|
||||
#undef HAVE_ASPRINTF
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the `gmtime_r' function. */
|
||||
#undef HAVE_GMTIME_R
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `mkstemps' function. */
|
||||
#undef HAVE_MKSTEMPS
|
||||
|
||||
/* Define to 1 if you have the `mlockall' function. */
|
||||
#undef HAVE_MLOCKALL
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strcasestr' function. */
|
||||
#undef HAVE_STRCASESTR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the `timegm' function. */
|
||||
#undef HAVE_TIMEGM
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* libtomcrypt uses the pre-1.18 PKCS #1 constant naming convention */
|
||||
#undef LIBTOMCRYPT_OLD_PKCS_NAMES
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* nettle uses the pre-3.x base64 API */
|
||||
#undef NETTLE_OLD_BASE64_API
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
#undef _POSIX_1_SOURCE
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,288 @@
|
|||
AC_PREREQ([2.61])
|
||||
AC_INIT([stoken], [0.92], [cernekee@gmail.com], [stoken], [http://stoken.sf.net/])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AM_INIT_AUTOMAKE([1.11 parallel-tests])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_LIBTOOL
|
||||
AC_GNU_SOURCE
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
LT_INIT([win32-dll])
|
||||
|
||||
# Upstream's pkg.m4 (since 0.27) offers this now, but define our own
|
||||
# compatible version in case the local version of pkgconfig isn't new enough.
|
||||
# https://bugs.freedesktop.org/show_bug.cgi?id=48743
|
||||
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
||||
[AC_ARG_WITH([pkgconfigdir],
|
||||
[AS_HELP_STRING([--with-pkgconfigdir],
|
||||
[install directory for stoken.pc pkg-config file])],
|
||||
[],[with_pkgconfigdir='$(libdir)/pkgconfig'])
|
||||
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
|
||||
|
||||
: ${CFLAGS=""}
|
||||
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
|
||||
# --enable-debug
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[debug],
|
||||
[AS_HELP_STRING([--enable-debug],[enable debugging code and output [default=no]])],
|
||||
[enable_debug=$enableval],
|
||||
[enable_debug="no"]
|
||||
)
|
||||
|
||||
if test "x$enable_debug" = xyes; then
|
||||
CFLAGS="$CFLAGS -O0 -ggdb -fno-inline"
|
||||
fi
|
||||
|
||||
# --enable-valgrind
|
||||
|
||||
AC_ARG_ENABLE([valgrind], [AS_HELP_STRING([--enable-valgrind],
|
||||
[use valgrind when running 'make check' [default=no]])],
|
||||
[enable_valgrind=$enableval],
|
||||
[enable_valgrind=no])
|
||||
|
||||
AM_CONDITIONAL([ENABLE_VALGRIND], [test $enable_valgrind != no])
|
||||
|
||||
EXTRA_PC_LIBS=""
|
||||
|
||||
AS_COMPILER_FLAGS(WFLAGS,
|
||||
"-Wall
|
||||
-Wextra
|
||||
-Wno-missing-field-initializers
|
||||
-Wno-sign-compare
|
||||
-Wno-pointer-sign
|
||||
-Wno-unused-parameter
|
||||
-Wno-unused-const-variable
|
||||
-Werror=pointer-to-int-cast
|
||||
-Wdeclaration-after-statement
|
||||
-Werror-implicit-function-declaration
|
||||
-Wformat-security
|
||||
-Winit-self
|
||||
-Wno-missing-declarations
|
||||
-Wmissing-include-dirs
|
||||
-Wnested-externs
|
||||
-Wpointer-arith
|
||||
-Wwrite-strings")
|
||||
AC_SUBST(WFLAGS, [$WFLAGS])
|
||||
|
||||
# mlockall() is missing on Bionic (Android)
|
||||
AC_CHECK_FUNCS([mlockall])
|
||||
|
||||
# mkstemps is missing on uClibc
|
||||
AC_CHECK_FUNCS([mkstemps])
|
||||
|
||||
# TODO: see if compatibility functions are needed to build on Darwin
|
||||
AC_CHECK_FUNCS([strcasestr asprintf])
|
||||
|
||||
# time functions are slightly different on Windows
|
||||
AC_CHECK_FUNCS([gmtime_r timegm])
|
||||
|
||||
# gtk / stoken-gui
|
||||
|
||||
AC_ARG_WITH([gtk], [AS_HELP_STRING([--with-gtk],
|
||||
[build stoken-gui for gtk+ @<:@default=check@:>@])],
|
||||
[],
|
||||
[with_gtk=check])
|
||||
|
||||
PKG_PROG_PKG_CONFIG
|
||||
if test "x$PKG_CONFIG" = x; then
|
||||
if test "x$with_gtk" = xyes; then
|
||||
AC_MSG_FAILURE([--with-gtk requires pkg-config])
|
||||
fi
|
||||
with_gtk=no
|
||||
fi
|
||||
|
||||
enable_gui=no
|
||||
AS_IF([test "x$with_gtk" != xno],
|
||||
[PKG_CHECK_MODULES([GTK], [gtk+-3.0],
|
||||
[enable_gui=yes],
|
||||
[if test "x$with_gtk" != xcheck; then
|
||||
AC_MSG_FAILURE(
|
||||
[--with-gtk was given, but test for gtk failed])
|
||||
fi
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
if test $enable_gui = yes; then
|
||||
AC_MSG_CHECKING([if gtk+ is usable])
|
||||
|
||||
saved_LIBS="$LIBS"
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
LIBS="$LIBS $GTK_LIBS"
|
||||
CFLAGS="$CFLAGS $GTK_CFLAGS"
|
||||
|
||||
AC_TRY_LINK([#include <gtk/gtk.h>
|
||||
#include <stdlib.h>],
|
||||
[gtk_init(NULL,NULL);],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[AC_MSG_FAILURE([unable to link gtk+ test program])])
|
||||
LIBS="$saved_LIBS"
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_GUI], [test $enable_gui = yes])
|
||||
|
||||
# libxml2 support for sdtid file parsing
|
||||
|
||||
PKG_CHECK_MODULES([LIBXML2], [libxml-2.0])
|
||||
|
||||
# crypto library (prefer tomcrypt if unspecified)
|
||||
|
||||
AC_ARG_WITH([tomcrypt], [AS_HELP_STRING([--with-tomcrypt],
|
||||
[use libtomcrypt for crypto @<:@default=check@:>@])],
|
||||
[with_tomcrypt=$withval],
|
||||
[with_tomcrypt=check])
|
||||
|
||||
AC_ARG_WITH([nettle], [AS_HELP_STRING([--with-nettle],
|
||||
[use nettle for crypto @<:@default=check@:>@])],
|
||||
[with_nettle=$withval],
|
||||
[with_nettle=check])
|
||||
|
||||
CRYPTO_BACKEND=""
|
||||
if test "$with_tomcrypt" != no -a "$with_nettle" != yes; then
|
||||
# libtomcrypt
|
||||
# Some distributions add a libtomcrypt.pc file, but it isn't in the
|
||||
# upstream libtomcrypt distribution so we can't count on it.
|
||||
tomcrypt_pkg=no
|
||||
|
||||
if test "x$PKG_CONFIG" != x; then
|
||||
PKG_CHECK_EXISTS([libtomcrypt], [tomcrypt_pkg=yes], [])
|
||||
fi
|
||||
|
||||
if test $tomcrypt_pkg = no; then
|
||||
AC_SUBST(TOMCRYPT_LIBS, [-ltomcrypt])
|
||||
AC_SUBST(DEPS_PC, [])
|
||||
TOMCRYPT_PC_LIBS="-ltomcrypt"
|
||||
else
|
||||
AC_SUBST(DEPS_PC, [libtomcrypt])
|
||||
PKG_CHECK_MODULES([TOMCRYPT], libtomcrypt)
|
||||
TOMCRYPT_PC_LIBS=
|
||||
fi
|
||||
|
||||
CRYPTO_LIBS="$TOMCRYPT_LIBS"
|
||||
CRYPTO_CFLAGS="-DLTM_DESC"
|
||||
|
||||
saved_LIBS="$LIBS"
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
LIBS="$LIBS $CRYPTO_LIBS"
|
||||
CFLAGS="$CFLAGS $CRYPTO_CFLAGS"
|
||||
|
||||
AC_MSG_CHECKING([if libtomcrypt is usable])
|
||||
AC_TRY_LINK([#include <tomcrypt.h>
|
||||
#include <stdlib.h>],
|
||||
[rijndael_ecb_encrypt(NULL,NULL,NULL);
|
||||
ltc_mp = ltm_desc;
|
||||
register_hash(&sha1_desc);],
|
||||
[AC_MSG_RESULT([yes])
|
||||
CRYPTO_BACKEND="tomcrypt"
|
||||
EXTRA_PC_LIBS="$EXTRA_PC_LIBS $TOMCRYPT_PC_LIBS"],
|
||||
[AC_MSG_RESULT([no])])
|
||||
|
||||
AC_MSG_CHECKING([whether libtomcrypt uses newer LTC_PKCS_1_V1_5 naming convention])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <tomcrypt.h>],
|
||||
[int padding = LTC_PKCS_1_V1_5;])],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_DEFINE([LIBTOMCRYPT_OLD_PKCS_NAMES], [1],
|
||||
[libtomcrypt uses the pre-1.18 PKCS #1 constant naming convention])])
|
||||
|
||||
LIBS="$saved_LIBS"
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
fi
|
||||
|
||||
if test -z "$CRYPTO_BACKEND" -a "$with_nettle" != no -a "$with_tomcrypt" != yes; then
|
||||
PKG_CHECK_MODULES(NETTLE, [nettle >= 2.4])
|
||||
PKG_CHECK_MODULES(HOGWEED, [hogweed >= 2.4])
|
||||
deps="nettle, hogweed"
|
||||
AC_SUBST(DEPS_PC, [$deps])
|
||||
|
||||
CRYPTO_CFLAGS="$NETTLE_CFLAGS $HOGWEED_CFLAGS"
|
||||
# gmp is added since we directly use GMP functions
|
||||
# unfortunately it doesn't show up in pkg-config
|
||||
CRYPTO_LIBS="$NETTLE_LIBS $HOGWEED_LIBS -lgmp"
|
||||
CRYPTO_BACKEND="nettle"
|
||||
|
||||
# nettle 2.x accepts a bidirectional (unsigned *) argument
|
||||
# nettle 3.x accepts a (size_t *) output-only argument
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Werror"
|
||||
AC_MSG_CHECKING([nettle base64 API version])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <nettle/base64.h>
|
||||
#include <stdlib.h>],
|
||||
[base64_decode_update(NULL, (size_t *)NULL, NULL, 0, NULL);])],
|
||||
AC_MSG_RESULT([3.0+]),
|
||||
[AC_MSG_RESULT([2.x])
|
||||
AC_DEFINE([NETTLE_OLD_BASE64_API], [1],
|
||||
[nettle uses the pre-3.x base64 API])])
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
fi
|
||||
|
||||
if test -z "$CRYPTO_BACKEND"; then
|
||||
AC_MSG_ERROR([Cannot find a suitable crypto library])
|
||||
fi
|
||||
|
||||
AC_SUBST(EXTRA_PC_LIBS, [$EXTRA_PC_LIBS])
|
||||
AC_SUBST(CRYPTO_CFLAGS, [$CRYPTO_CFLAGS])
|
||||
AC_SUBST(CRYPTO_LIBS, [$CRYPTO_LIBS])
|
||||
AC_SUBST(CRYPTO_BACKEND, [$CRYPTO_BACKEND])
|
||||
|
||||
# JNI
|
||||
|
||||
AC_ARG_WITH([java],
|
||||
AS_HELP_STRING([--with-java(=DIR)],
|
||||
[Build JNI bindings using jni.h from DIR [default=no]]),
|
||||
[], [with_java=no])
|
||||
|
||||
if test "$with_java" = "yes"; then
|
||||
AX_JNI_INCLUDE_DIR
|
||||
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
|
||||
JNI_CFLAGS="$JNI_CFLAGS -I$JNI_INCLUDE_DIR"
|
||||
done
|
||||
elif test "$with_java" = "no"; then
|
||||
JNI_CFLAGS=""
|
||||
else
|
||||
JNI_CFLAGS="-I$with_java"
|
||||
fi
|
||||
|
||||
if test "x$JNI_CFLAGS" != "x"; then
|
||||
oldCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $JNI_CFLAGS"
|
||||
AC_MSG_CHECKING([jni.h usability])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <jni.h>],
|
||||
[jint foo = 0; (void)foo;])],
|
||||
AC_MSG_RESULT([yes]),
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([unable to compile JNI test program])])
|
||||
CFLAGS="$oldCFLAGS"
|
||||
|
||||
AC_SUBST(JNI_CFLAGS, [$JNI_CFLAGS])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(USE_JNI, [test "$JNI_CFLAGS" != ""])
|
||||
|
||||
AC_ARG_ENABLE([jni-standalone],
|
||||
AS_HELP_STRING([--enable-jni-standalone],
|
||||
[build JNI stubs directly into libstoken.so [default=no]]),
|
||||
[jni_standalone=$enableval],
|
||||
[jni_standalone=no])
|
||||
AM_CONDITIONAL(JNI_STANDALONE, [test $jni_standalone = yes])
|
||||
|
||||
# library version
|
||||
|
||||
AX_CHECK_VSCRIPT
|
||||
|
||||
libhdr=${srcdir}/src/stoken.h
|
||||
APIMAJOR="`awk '/#define STOKEN_API_VER_MAJOR/ {print $3}' ${libhdr}`"
|
||||
APIMINOR="`awk '/#define STOKEN_API_VER_MINOR/ {print $3}' ${libhdr}`"
|
||||
AC_SUBST(APIMAJOR)
|
||||
AC_SUBST(APIMINOR)
|
||||
|
||||
AC_CONFIG_FILES(stoken.pc)
|
||||
AC_OUTPUT
|
|
@ -0,0 +1,2 @@
|
|||
*.o
|
||||
libstoken-test
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* libstoken-test.c - example program illustrating the use of libstoken
|
||||
*
|
||||
* Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Build instructions:
|
||||
*
|
||||
* CFLAGS=`pkg-config --cflags stoken`
|
||||
* LIBS=`pkg-config --libs stoken`
|
||||
* gcc -c libstoken-test.c -o libstoken-test.o $CFLAGS
|
||||
* gcc libstoken-test.o -o libstoken-test $LIBS
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* # generate tokencode from ~/.stokenrc (if present)
|
||||
* ./libstoken-test
|
||||
*
|
||||
* # generate tokencode from a different stokenrc file
|
||||
* ./libstoken-test /tmp/stokenrc
|
||||
*
|
||||
* # generate tokencode from a token string provided on the command line
|
||||
* ./libstoken-test 252503079680743142131101346153112272336172670304467711744173124152503452716757206
|
||||
*
|
||||
* # generate tokencode from an sdtid XML file
|
||||
* ./libstoken-test "`cat foo.sdtid`"
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stoken.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define BUFLEN 64
|
||||
|
||||
static void die(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fflush(stdout);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int raw_read_user_input(char *out, int max_len)
|
||||
{
|
||||
char *p;
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
if (fgets(out, max_len, stdin) == NULL) {
|
||||
*out = 0;
|
||||
return 0;
|
||||
}
|
||||
p = strchr(out, '\n');
|
||||
if (p)
|
||||
*p = 0;
|
||||
return strlen(out);
|
||||
}
|
||||
|
||||
static struct termios oldtio;
|
||||
static void stdin_echo(int enable_echo);
|
||||
|
||||
static void restore_tio(int sig)
|
||||
{
|
||||
stdin_echo(1);
|
||||
puts("");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void stdin_echo(int enable_echo)
|
||||
{
|
||||
struct termios tio;
|
||||
struct sigaction sa;
|
||||
const int fd = 0;
|
||||
|
||||
if (!enable_echo) {
|
||||
/* ripped from busybox bb_ask() */
|
||||
tcgetattr(fd, &oldtio);
|
||||
tcflush(fd, TCIFLUSH);
|
||||
tio = oldtio;
|
||||
|
||||
tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL);
|
||||
tcsetattr(fd, TCSANOW, &tio);
|
||||
|
||||
/* restore a sane terminal state if interrupted */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = &restore_tio;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
} else
|
||||
tcsetattr(fd, TCSANOW, &oldtio);
|
||||
}
|
||||
|
||||
static void prompt(const char *msg, char *out, int max_len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
printf("%s", msg);
|
||||
|
||||
stdin_echo(0);
|
||||
rc = raw_read_user_input(out, max_len);
|
||||
stdin_echo(1);
|
||||
puts("");
|
||||
|
||||
if (rc == 0)
|
||||
die("Aborting...\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct stoken_ctx *ctx = stoken_new();
|
||||
char devid[BUFLEN] = { 0 }, pass[BUFLEN] = { 0 }, pin[BUFLEN] = { 0 };
|
||||
char out[STOKEN_MAX_TOKENCODE + 1];
|
||||
int rc;
|
||||
|
||||
if (argc >= 2) {
|
||||
char *s = argv[1];
|
||||
if (*s == '1' || *s == '2' || *s == '<') {
|
||||
rc = stoken_import_string(ctx, s);
|
||||
if (rc)
|
||||
die("stoken_import_string returned %d\n", rc);
|
||||
} else {
|
||||
rc = stoken_import_rcfile(ctx, s);
|
||||
if (rc)
|
||||
die("stoken_import_rcfile returned %d\n", rc);
|
||||
}
|
||||
} else {
|
||||
rc = stoken_import_rcfile(ctx, NULL);
|
||||
if (rc)
|
||||
die("stoken_import_rcfile returned %d\n", rc);
|
||||
}
|
||||
|
||||
if (stoken_devid_required(ctx))
|
||||
prompt("Device ID: ", devid, BUFLEN);
|
||||
if (stoken_pass_required(ctx))
|
||||
prompt("Password: ", pass, BUFLEN);
|
||||
|
||||
rc = stoken_decrypt_seed(ctx, pass, devid);
|
||||
if (rc)
|
||||
die("stoken_decrypt_seed returned %d\n", rc);
|
||||
|
||||
if (stoken_pin_required(ctx))
|
||||
prompt("PIN: ", pin, BUFLEN);
|
||||
|
||||
rc = stoken_compute_tokencode(ctx, time(NULL), pin, out);
|
||||
if (rc)
|
||||
die("stoken_compute_tokencode returned %d\n", rc);
|
||||
printf("Tokencode: %s\n", out);
|
||||
|
||||
stoken_destroy(ctx);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Sample script to encode a token as a QR code. Requires "display" from
|
||||
# ImageMagick, and qrencode. The input token must not be protected with
|
||||
# a password or device ID.
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
if [ -e "$1" ]; then
|
||||
args="--file $1"
|
||||
else
|
||||
args="--token $1"
|
||||
fi
|
||||
else
|
||||
args=""
|
||||
fi
|
||||
|
||||
token=$(stoken export --batch --android $args 2> /dev/null)
|
||||
if [ $? != 0 ]; then
|
||||
echo "usage: $0 [ { <token_string> | <sdtid_file> } ]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -ex
|
||||
|
||||
png=$(mktemp /tmp/qr-XXXXXX.png)
|
||||
qrencode -o $png -l H "$token"
|
||||
display $png
|
||||
rm -f $png
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,138 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use XML::LibXML;
|
||||
|
||||
my $stoken = "stoken";
|
||||
my $tc = "TokenConverter";
|
||||
|
||||
# --once means exit after the first try, leaving a sample sdtid file in cwd
|
||||
my $once = 0;
|
||||
|
||||
sub add_str_node($$$)
|
||||
{
|
||||
my ($parent, $name, $value) = @_;
|
||||
my $doc = $parent->ownerDocument;
|
||||
my $node = $doc->createElement($name);
|
||||
$node->appendChild($doc->createTextNode($value));
|
||||
$parent->appendChild($node);
|
||||
}
|
||||
|
||||
sub rand_str
|
||||
{
|
||||
my ($len) = @_;
|
||||
my $max_rand = 28;
|
||||
if (!defined($len)) {
|
||||
$len = int(rand() * $max_rand) + 5;
|
||||
}
|
||||
|
||||
my $ret = "";
|
||||
while (1) {
|
||||
my $c = chr(32 + int(rand() * 95));
|
||||
|
||||
# these expand to 2-byte sequences. see mangle_encoding()
|
||||
if ($c eq '&' || $c eq '<' || $c eq '>') {
|
||||
$len -= 2;
|
||||
} else {
|
||||
$len--;
|
||||
}
|
||||
if ($len <= 0) {
|
||||
last;
|
||||
}
|
||||
$ret .= $c;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub rand_bool()
|
||||
{
|
||||
return int(rand() * 2);
|
||||
}
|
||||
|
||||
sub random_doc()
|
||||
{
|
||||
my $doc = XML::LibXML::Document->new('1.0');
|
||||
my $root = $doc->createElement("TKNBatch");
|
||||
$doc->setDocumentElement($root);
|
||||
|
||||
my $node = $doc->createElement("TKNHeader");
|
||||
$root->appendChild($node);
|
||||
add_str_node($node, "Version", "0");
|
||||
add_str_node($node, "Origin", rand_str());
|
||||
add_str_node($node, "Dest", rand_str());
|
||||
add_str_node($node, "Name", rand_str(16));
|
||||
add_str_node($node, "FirstToken", rand_str());
|
||||
add_str_node($node, "LastToken", rand_str());
|
||||
# NumTokens: default
|
||||
add_str_node($node, "DefAddPIN", rand_bool());
|
||||
add_str_node($node, "DefLocalPIN", rand_bool());
|
||||
add_str_node($node, "DefCopyProtection", rand_bool());
|
||||
add_str_node($node, "DefPinType", rand_bool());
|
||||
add_str_node($node, "DefKeypad", rand_bool());
|
||||
add_str_node($node, "DefProtLevel", rand_bool());
|
||||
add_str_node($node, "DefRevision", rand_bool());
|
||||
add_str_node($node, "DefTimeDerivedSeeds", rand_bool());
|
||||
add_str_node($node, "DefAppDerivedSeeds", rand_bool());
|
||||
# DefFormFactor: default
|
||||
# HeaderMAC: computed
|
||||
|
||||
my $tkn = $doc->createElement("TKN");
|
||||
$root->appendChild($tkn);
|
||||
# SN: random
|
||||
# Seed: random
|
||||
add_str_node($tkn, "UserFirstName", rand_str());
|
||||
add_str_node($tkn, "UserLastName", rand_str());
|
||||
add_str_node($tkn, "UserLogin", rand_str());
|
||||
|
||||
$node = $doc->createElement("TokenAttributes");
|
||||
$tkn->appendChild($node);
|
||||
# DeviceSerialNumber: blank
|
||||
add_str_node($node, "Nickname", rand_str());
|
||||
# TokenMAC: computed
|
||||
|
||||
$node = $doc->createElement("TKNTrailer");
|
||||
$root->appendChild($node);
|
||||
add_str_node($node, "BatchSignature", rand_str(100));
|
||||
add_str_node($node, "BatchCertificate", rand_str(500));
|
||||
return $doc;
|
||||
}
|
||||
|
||||
#
|
||||
# MAIN
|
||||
#
|
||||
|
||||
# allow running from the source dir
|
||||
if (-x "../stoken") {
|
||||
$ENV{'PATH'} = "..:".$ENV{'PATH'};
|
||||
}
|
||||
|
||||
while (@ARGV != 0) {
|
||||
my $a = $ARGV[0];
|
||||
shift @ARGV;
|
||||
|
||||
if ($a eq "--once") {
|
||||
$once = 1;
|
||||
} else {
|
||||
die "unknown arg: '$a'";
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
my $doc = random_doc();
|
||||
open(F, ">tpl.xml") or die;
|
||||
print F $doc->toString(1);
|
||||
close(F);
|
||||
|
||||
system("$stoken export --random --template tpl.xml --sdtid > out.sdtid") == 0
|
||||
or die "can't run stoken";
|
||||
system("$tc out.sdtid > ctf.txt") == 0 or die "TokenConverter failed";
|
||||
|
||||
system("$stoken show --file ctf.txt --seed | head -n 2 > seed.txt")
|
||||
== 0 or die "can't read seed from ctf";
|
||||
system("$stoken show --file out.sdtid --seed | head -n 2 > seed-test.txt")
|
||||
== 0 or die "can't read seed from sdtid";
|
||||
|
||||
system("cmp seed.txt seed-test.txt") == 0 or die "seed mismatch";
|
||||
} while (!$once);
|
||||
|
||||
exit 0;
|
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.16.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.0"/>
|
||||
<object class="GtkDialog" id="dialog_window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">10</property>
|
||||
<property name="title" translatable="yes">Software Token</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="dialog-vbox1">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">2</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox" id="dialog-action_area1">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="ok_button">
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="neg_button">
|
||||
<property name="label">gtk-quit</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="yalign">0.62000000476837158</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-dialog-authentication</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">10</property>
|
||||
<property name="label" translatable="yes"><span size="xx-large">Password required</span></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Please enter the password to unlock this software token.</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="is_focus">True</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">10</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="activates_default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="-5">ok_button</action-widget>
|
||||
<action-widget response="-6">neg_button</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
</interface>
|
|
@ -0,0 +1,148 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.16.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.0"/>
|
||||
<object class="GtkDialog" id="dialog_window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">10</property>
|
||||
<property name="title" translatable="yes">Software Token</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="dialog-vbox1">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">2</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox" id="dialog-action_area1">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="ok_button">
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="neg_button">
|
||||
<property name="label">Skip</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="yalign">0.62000000476837158</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-dialog-authentication</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">10</property>
|
||||
<property name="label" translatable="yes"><span size="xx-large">PIN required</span></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Please enter your PIN.</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="is_focus">True</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">10</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="activates_default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="-5">ok_button</action-widget>
|
||||
<action-widget response="-6">neg_button</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
</interface>
|
|
@ -0,0 +1,10 @@
|
|||
[Desktop Entry]
|
||||
Name=Software Token (small)
|
||||
GenericName=Software Token
|
||||
Comment=RSA SecurID-compatible software token
|
||||
Exec=stoken-gui --small
|
||||
Icon=stoken-gui
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Security;GTK;Utility;
|
||||
Keywords=RSA;SecurID;Authenticator;
|
|
@ -0,0 +1,10 @@
|
|||
[Desktop Entry]
|
||||
Name=Software Token
|
||||
GenericName=Software Token
|
||||
Comment=RSA SecurID-compatible software token
|
||||
Exec=stoken-gui
|
||||
Icon=stoken-gui
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Security;GTK;Utility;
|
||||
Keywords=RSA;SecurID;Authenticator;
|
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,327 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.16.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.0"/>
|
||||
<object class="GtkWindow" id="app_window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">10</property>
|
||||
<property name="title" translatable="yes">Software Token</property>
|
||||
<property name="default_width">300</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="tokencode_text">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes"><span size="xx-large" weight="bold">0000 0000</span></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDrawingArea" id="progress_bar">
|
||||
<property name="height_request">10</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="copy_button">
|
||||
<property name="label" translatable="yes">_Copy</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="relief">none</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="separator1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkEventBox" id="next_tokencode_eventbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Click to copy to clipboard</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Next tokencode:</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="next_tokencode_text">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box6">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="label" translatable="yes">Using PIN:</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="using_pin_text">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="separator2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box7">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkEventBox" id="eventbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Click to copy to clipboard</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box8">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Token S/N:</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="token_sn_text">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box9">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box10">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="label" translatable="yes">Expiration date:</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="exp_date_text">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.16.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.0"/>
|
||||
<object class="GtkWindow" id="app_window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">10</property>
|
||||
<property name="title" translatable="yes">Software Token</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="has_resize_grip">False</property>
|
||||
<child>
|
||||
<object class="GtkEventBox" id="event_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Click to copy to clipboard</property>
|
||||
<child>
|
||||
<object class="GtkFrame" id="tokencode_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="top_padding">10</property>
|
||||
<property name="bottom_padding">10</property>
|
||||
<property name="left_padding">10</property>
|
||||
<property name="right_padding">10</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="tokencode_text">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes"><span size="xx-large" weight="bold">0000 0000</span></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDrawingArea" id="progress_bar">
|
||||
<property name="height_request">10</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="small_tokencode_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Tokencode</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
|
@ -0,0 +1,2 @@
|
|||
build/
|
||||
dist/
|
|
@ -0,0 +1,18 @@
|
|||
Description:
|
||||
|
||||
This directory contains a JNI interface layer for libstoken, and a
|
||||
demo program to show how it can be used.
|
||||
|
||||
Build instructions:
|
||||
|
||||
From the top level, run:
|
||||
|
||||
./configure --with-java
|
||||
make
|
||||
cd java
|
||||
ant
|
||||
java -Djava.library.path=../.libs -jar dist/example.jar \
|
||||
{ <token_string> | <stokenrc_path> }
|
||||
|
||||
Test/demo code is in src/com/example/
|
||||
LibStoken wrapper library is in src/org/stoken/
|
|
@ -0,0 +1,33 @@
|
|||
<project name="LibStoken" default="dist" basedir=".">
|
||||
<property name="build" location="build"/>
|
||||
<property name="dist" location="dist"/>
|
||||
<property name="src" location="src"/>
|
||||
|
||||
<property name="jar_lib" location="${dist}/stoken-wrapper.jar"/>
|
||||
<property name="jar_app" location="${dist}/example.jar"/>
|
||||
|
||||
<target name="init">
|
||||
<mkdir dir="${build}"/>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="init">
|
||||
<javac srcdir="${src}" destdir="${build}"
|
||||
includeantruntime="false"/>
|
||||
</target>
|
||||
|
||||
<target name="dist" depends="compile">
|
||||
<jar jarfile="${jar_lib}" basedir="${build}"
|
||||
includes="org/stoken/*" />
|
||||
|
||||
<jar jarfile="${jar_app}" basedir="${build}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="com.example.LibTest" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="${build}"/>
|
||||
<delete dir="${dist}"/>
|
||||
</target>
|
||||
</project>
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* LibTest.java - stoken Java test program
|
||||
*
|
||||
* Copyright 2014 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.example;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
import org.stoken.LibStoken;
|
||||
|
||||
public final class LibTest {
|
||||
|
||||
private static void die(String msg) {
|
||||
System.out.println(msg);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private static void die(String msg, int error) {
|
||||
String errors[] = { "SUCCESS", "INVALID_FORMAT", "IO_ERROR", "FILE_NOT_FOUND" };
|
||||
error = -error;
|
||||
if (error < errors.length) {
|
||||
die(msg + ": " + errors[error]);
|
||||
} else {
|
||||
die(msg + ": unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
private static String getline(String prompt) {
|
||||
System.out.print(prompt);
|
||||
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
|
||||
try {
|
||||
String line = br.readLine();
|
||||
return line;
|
||||
} catch (IOException e) {
|
||||
die("\nI/O error");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void main(String argv[]) {
|
||||
System.loadLibrary("stoken-wrapper");
|
||||
LibStoken lib = new LibStoken();
|
||||
|
||||
if (argv.length != 1) {
|
||||
die("usage: LibTest { <token_string> | <stokenrc_path> }");
|
||||
}
|
||||
|
||||
int ret = lib.importRCFile(argv[0]);
|
||||
if (ret != LibStoken.SUCCESS) {
|
||||
ret = lib.importString(argv[0]);
|
||||
if (ret != LibStoken.SUCCESS) {
|
||||
die("Can't parse token string", ret);
|
||||
}
|
||||
}
|
||||
|
||||
String devID = null;
|
||||
if (lib.isDevIDRequired()) {
|
||||
devID = getline("Enter Device ID: ");
|
||||
}
|
||||
if (!lib.checkDevID(devID)) {
|
||||
die("Device ID does not match token");
|
||||
}
|
||||
|
||||
String pass = null;
|
||||
if (lib.isPassRequired()) {
|
||||
pass = getline("Enter password: ");
|
||||
}
|
||||
|
||||
ret = lib.decryptSeed(pass, devID);
|
||||
if (ret != LibStoken.SUCCESS) {
|
||||
die("Unable to decrypt seed", ret);
|
||||
}
|
||||
|
||||
LibStoken.StokenInfo info = lib.getInfo();
|
||||
|
||||
System.out.println("SN: " + info.serial);
|
||||
|
||||
Date d = new Date(info.unixExpDate * 1000);
|
||||
System.out.println("Exp: " + new SimpleDateFormat("yyyy-MM-dd").format(d));
|
||||
|
||||
String PIN = null;
|
||||
if (lib.isPINRequired()) {
|
||||
PIN = getline("Enter PIN: ");
|
||||
}
|
||||
if (!lib.checkPIN(PIN)) {
|
||||
die("Invalid PIN format");
|
||||
}
|
||||
|
||||
String tokencode = lib.computeTokencode(0, PIN);
|
||||
if (tokencode == null) {
|
||||
die("Unable to compute tokencode");
|
||||
}
|
||||
System.out.println("TOKENCODE: " + tokencode);
|
||||
|
||||
lib.destroy();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* LibStoken.java - Java wrapper for libstoken.so
|
||||
*
|
||||
* Copyright 2014 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.stoken;
|
||||
|
||||
public class LibStoken {
|
||||
|
||||
/* constants */
|
||||
|
||||
public static final int SUCCESS = 0;
|
||||
public static final int INVALID_FORMAT = -1;
|
||||
public static final int IO_ERROR = -2;
|
||||
public static final int FILE_NOT_FOUND = -3;
|
||||
|
||||
/* create/destroy library instances */
|
||||
|
||||
public LibStoken() {
|
||||
libctx = init();
|
||||
}
|
||||
|
||||
public synchronized void destroy() {
|
||||
if (libctx != 0) {
|
||||
free();
|
||||
libctx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StokenInfo {
|
||||
public String serial;
|
||||
public long unixExpDate;
|
||||
public int interval;
|
||||
public int tokenVersion;
|
||||
public boolean usesPin;
|
||||
};
|
||||
|
||||
public static class StokenGUID {
|
||||
public String tag;
|
||||
public String longName;
|
||||
public String GUID;
|
||||
}
|
||||
|
||||
/* public APIs */
|
||||
|
||||
public synchronized native int importRCFile(String path);
|
||||
public synchronized native int importString(String str);
|
||||
public synchronized native StokenInfo getInfo();
|
||||
public synchronized native int getMinPIN();
|
||||
public synchronized native int getMaxPIN();
|
||||
public synchronized native boolean isPINRequired();
|
||||
public synchronized native boolean isPassRequired();
|
||||
public synchronized native boolean isDevIDRequired();
|
||||
public synchronized native boolean checkPIN(String PIN);
|
||||
public synchronized native boolean checkDevID(String DevID);
|
||||
public synchronized native StokenGUID[] getGUIDList();
|
||||
public synchronized native int decryptSeed(String pass, String devID);
|
||||
public synchronized native String encryptSeed(String pass, String devID);
|
||||
public synchronized native String computeTokencode(long when, String PIN);
|
||||
public synchronized native String formatTokencode(String tokencode);
|
||||
|
||||
/* LibStoken internals */
|
||||
|
||||
long libctx;
|
||||
synchronized native long init();
|
||||
synchronized native void free();
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
STOKEN_1.0 {
|
||||
global:
|
||||
stoken_new;
|
||||
stoken_destroy;
|
||||
stoken_import_rcfile;
|
||||
stoken_import_string;
|
||||
stoken_pin_range;
|
||||
stoken_pin_required;
|
||||
stoken_pass_required;
|
||||
stoken_devid_required;
|
||||
stoken_check_pin;
|
||||
stoken_decrypt_seed;
|
||||
stoken_compute_tokencode;
|
||||
};
|
||||
|
||||
STOKEN_1.1 {
|
||||
global:
|
||||
stoken_check_devid;
|
||||
stoken_encrypt_seed;
|
||||
} STOKEN_1.0;
|
||||
|
||||
STOKEN_1.2 {
|
||||
global:
|
||||
stoken_get_info;
|
||||
} STOKEN_1.1;
|
||||
|
||||
STOKEN_1.3 {
|
||||
global:
|
||||
stoken_format_tokencode;
|
||||
stoken_get_guid_list;
|
||||
} STOKEN_1.2;
|
||||
|
||||
STOKEN_PRIVATE {
|
||||
global:
|
||||
securid_check_devid;
|
||||
securid_check_exp;
|
||||
securid_compute_tokencode;
|
||||
securid_decode_token;
|
||||
securid_decrypt_pin;
|
||||
securid_decrypt_seed;
|
||||
securid_devid_required;
|
||||
securid_encode_token;
|
||||
securid_encrypt_pin;
|
||||
securid_pass_required;
|
||||
securid_pin_format_ok;
|
||||
securid_pin_required;
|
||||
securid_random_token;
|
||||
securid_token_info;
|
||||
securid_token_interval;
|
||||
securid_unix_exp_date;
|
||||
sdtid_decode;
|
||||
sdtid_decrypt;
|
||||
sdtid_issue;
|
||||
sdtid_export;
|
||||
sdtid_free;
|
||||
stc_standalone_init;
|
||||
__stoken_parse_and_decode_token;
|
||||
__stoken_read_rcfile;
|
||||
__stoken_write_rcfile;
|
||||
__stoken_zap_rcfile_data;
|
||||
stoken__strcasestr;
|
||||
stoken__mkstemps;
|
||||
/* NOTE: this can break non-GNU toolchains */
|
||||
Java_*;
|
||||
local:
|
||||
*;
|
||||
};
|
|
@ -0,0 +1,63 @@
|
|||
dnl
|
||||
dnl http://cgit.freedesktop.org/swfdec/swfdec/plain/m4/as-compiler-flag.m4
|
||||
dnl as-compiler-flag.m4 0.1.0
|
||||
|
||||
dnl autostars m4 macro for detection of compiler flags
|
||||
|
||||
dnl David Schleef <ds@schleef.org>
|
||||
|
||||
dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $
|
||||
|
||||
dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED])
|
||||
dnl Tries to compile with the given CFLAGS.
|
||||
dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags,
|
||||
dnl and ACTION-IF-NOT-ACCEPTED otherwise.
|
||||
|
||||
AC_DEFUN([AS_COMPILER_FLAG],
|
||||
[
|
||||
AC_MSG_CHECKING([to see if compiler understands $1])
|
||||
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $1"
|
||||
|
||||
AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
if test "X$flag_ok" = Xyes ; then
|
||||
m4_ifvaln([$2],[$2])
|
||||
true
|
||||
else
|
||||
m4_ifvaln([$3],[$3])
|
||||
true
|
||||
fi
|
||||
AC_MSG_RESULT([$flag_ok])
|
||||
])
|
||||
|
||||
dnl AS_COMPILER_FLAGS(VAR, FLAGS)
|
||||
dnl Tries to compile with the given CFLAGS.
|
||||
|
||||
AC_DEFUN([AS_COMPILER_FLAGS],
|
||||
[
|
||||
list=$2
|
||||
flags_supported=""
|
||||
flags_unsupported=""
|
||||
AC_MSG_CHECKING([for supported compiler flags])
|
||||
for each in $list
|
||||
do
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $each"
|
||||
AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
if test "X$flag_ok" = Xyes ; then
|
||||
flags_supported="$flags_supported $each"
|
||||
else
|
||||
flags_unsupported="$flags_unsupported $each"
|
||||
fi
|
||||
done
|
||||
AC_MSG_RESULT([$flags_supported])
|
||||
if test "X$flags_unsupported" != X ; then
|
||||
AC_MSG_WARN([unsupported compiler flags: $flags_unsupported])
|
||||
fi
|
||||
$1="$$1 $flags_supported"
|
||||
])
|
|
@ -0,0 +1,142 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_check_vscript.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CHECK_VSCRIPT
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check whether the linker supports version scripts. Version scripts are
|
||||
# used when building shared libraries to bind symbols to version nodes
|
||||
# (helping to detect incompatibilities) or to limit the visibility of
|
||||
# non-public symbols.
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# If version scripts are supported, VSCRIPT_LDFLAGS will contain the
|
||||
# appropriate flag to pass to the linker. On GNU systems this would
|
||||
# typically be "-Wl,--version-script", and on Solaris it would
|
||||
# typically be "-Wl,-M".
|
||||
#
|
||||
# Two Automake conditionals are also set:
|
||||
#
|
||||
# HAVE_VSCRIPT is true if the linker supports version scripts with
|
||||
# entries that use simple wildcards, like "local: *".
|
||||
#
|
||||
# HAVE_VSCRIPT_COMPLEX is true if the linker supports version scripts with
|
||||
# pattern matching wildcards, like "global: Java_*".
|
||||
#
|
||||
# On systems that do not support symbol versioning, such as Mac OS X, both
|
||||
# conditionals will be false. They will also be false if the user passes
|
||||
# "--disable-symvers" on the configure command line.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# configure.ac:
|
||||
#
|
||||
# AX_CHECK_VSCRIPT
|
||||
#
|
||||
# Makefile.am:
|
||||
#
|
||||
# if HAVE_VSCRIPT
|
||||
# libfoo_la_LDFLAGS += $(VSCRIPT_LDFLAGS),@srcdir@/libfoo.map
|
||||
# endif
|
||||
#
|
||||
# if HAVE_VSCRIPT_COMPLEX
|
||||
# libbar_la_LDFLAGS += $(VSCRIPT_LDFLAGS),@srcdir@/libbar.map
|
||||
# endif
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2014 Kevin Cernekee <cernekee@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 1
|
||||
|
||||
# _AX_CHECK_VSCRIPT(flag, global-sym, action-if-link-succeeds, [junk-file=no])
|
||||
AC_DEFUN([_AX_CHECK_VSCRIPT], [
|
||||
AC_LANG_PUSH([C])
|
||||
ax_check_vscript_save_flags="$LDFLAGS"
|
||||
echo "V1 { global: $2; local: *; };" > conftest.map
|
||||
AS_IF([test x$4 = xyes], [
|
||||
echo "{" >> conftest.map
|
||||
])
|
||||
LDFLAGS="$LDFLAGS -Wl,$1,conftest.map"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[int show, hide;]], [])], [$3])
|
||||
LDFLAGS="$ax_check_vscript_save_flags"
|
||||
rm -f conftest.map
|
||||
AC_LANG_POP([C])
|
||||
]) dnl _AX_CHECK_VSCRIPT
|
||||
|
||||
AC_DEFUN([AX_CHECK_VSCRIPT], [
|
||||
|
||||
AC_ARG_ENABLE([symvers],
|
||||
AS_HELP_STRING([--disable-symvers],
|
||||
[disable library symbol versioning [default=auto]]),
|
||||
[want_symvers=$enableval],
|
||||
[want_symvers=yes]
|
||||
)
|
||||
|
||||
AS_IF([test x$want_symvers = xyes], [
|
||||
|
||||
dnl First test --version-script and -M with a simple wildcard.
|
||||
|
||||
AC_CACHE_CHECK([linker version script flag], ax_cv_check_vscript_flag, [
|
||||
ax_cv_check_vscript_flag=unsupported
|
||||
_AX_CHECK_VSCRIPT([--version-script], [show], [
|
||||
ax_cv_check_vscript_flag=--version-script
|
||||
])
|
||||
AS_IF([test x$ax_cv_check_vscript_flag = xunsupported], [
|
||||
_AX_CHECK_VSCRIPT([-M], [show], [ax_cv_check_vscript_flag=-M])
|
||||
])
|
||||
|
||||
dnl The linker may interpret -M (no argument) as "produce a load map."
|
||||
dnl If "-M conftest.map" doesn't fail when conftest.map contains
|
||||
dnl obvious syntax errors, assume this is the case.
|
||||
|
||||
AS_IF([test x$ax_cv_check_vscript_flag != xunsupported], [
|
||||
_AX_CHECK_VSCRIPT([$ax_cv_check_vscript_flag], [show],
|
||||
[ax_cv_check_vscript_flag=unsupported], [yes])
|
||||
])
|
||||
])
|
||||
|
||||
dnl If the simple wildcard worked, retest with a complex wildcard.
|
||||
|
||||
AS_IF([test x$ax_cv_check_vscript_flag != xunsupported], [
|
||||
ax_check_vscript_flag=$ax_cv_check_vscript_flag
|
||||
AC_CACHE_CHECK([if version scripts can use complex wildcards],
|
||||
ax_cv_check_vscript_complex_wildcards, [
|
||||
ax_cv_check_vscript_complex_wildcards=no
|
||||
_AX_CHECK_VSCRIPT([$ax_cv_check_vscript_flag], [sh*], [
|
||||
ax_cv_check_vscript_complex_wildcards=yes])
|
||||
])
|
||||
ax_check_vscript_complex_wildcards="$ax_cv_check_vscript_complex_wildcards"
|
||||
], [
|
||||
ax_check_vscript_flag=
|
||||
ax_check_vscript_complex_wildcards=no
|
||||
])
|
||||
], [
|
||||
AC_MSG_CHECKING([linker version script flag])
|
||||
AC_MSG_RESULT([disabled])
|
||||
|
||||
ax_check_vscript_flag=
|
||||
ax_check_vscript_complex_wildcards=no
|
||||
])
|
||||
|
||||
AS_IF([test x$ax_check_vscript_flag != x], [
|
||||
VSCRIPT_LDFLAGS="-Wl,$ax_check_vscript_flag"
|
||||
AC_SUBST([VSCRIPT_LDFLAGS])
|
||||
])
|
||||
|
||||
AM_CONDITIONAL([HAVE_VSCRIPT],
|
||||
[test x$ax_check_vscript_flag != x])
|
||||
AM_CONDITIONAL([HAVE_VSCRIPT_COMPLEX],
|
||||
[test x$ax_check_vscript_complex_wildcards = xyes])
|
||||
|
||||
]) dnl AX_CHECK_VSCRIPT
|
|
@ -0,0 +1,132 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_JNI_INCLUDE_DIR
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
|
||||
# programs using the JNI interface.
|
||||
#
|
||||
# JNI include directories are usually in the Java distribution. This is
|
||||
# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
|
||||
# that order. When this macro completes, a list of directories is left in
|
||||
# the variable JNI_INCLUDE_DIRS.
|
||||
#
|
||||
# Example usage follows:
|
||||
#
|
||||
# AX_JNI_INCLUDE_DIR
|
||||
#
|
||||
# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
|
||||
# do
|
||||
# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
|
||||
# done
|
||||
#
|
||||
# If you want to force a specific compiler:
|
||||
#
|
||||
# - at the configure.in level, set JAVAC=yourcompiler before calling
|
||||
# AX_JNI_INCLUDE_DIR
|
||||
#
|
||||
# - at the configure level, setenv JAVAC
|
||||
#
|
||||
# Note: This macro can work with the autoconf M4 macros for Java programs.
|
||||
# This particular macro is not part of the original set of macros.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 11
|
||||
|
||||
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
|
||||
AC_DEFUN([AX_JNI_INCLUDE_DIR],[
|
||||
|
||||
JNI_INCLUDE_DIRS=""
|
||||
|
||||
if test "x$JAVA_HOME" != x; then
|
||||
_JTOPDIR="$JAVA_HOME"
|
||||
else
|
||||
if test "x$JAVAC" = x; then
|
||||
JAVAC=javac
|
||||
fi
|
||||
AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
|
||||
if test "x$_ACJNI_JAVAC" = xno; then
|
||||
AC_MSG_ERROR([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
|
||||
fi
|
||||
_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
|
||||
_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
|
||||
fi
|
||||
|
||||
case "$host_os" in
|
||||
darwin*) # Apple JDK is at /System location and has headers symlinked elsewhere
|
||||
case "$_JTOPDIR" in
|
||||
/System/Library/Frameworks/JavaVM.framework/*)
|
||||
_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||
_JINC="$_JTOPDIR/Headers";;
|
||||
*) _JINC="$_JTOPDIR/include";;
|
||||
esac;;
|
||||
*) _JINC="$_JTOPDIR/include";;
|
||||
esac
|
||||
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
|
||||
_AS_ECHO_LOG([_JINC=$_JINC])
|
||||
|
||||
# On Mac OS X 10.6.4, jni.h is a symlink:
|
||||
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
|
||||
# -> ../../CurrentJDK/Headers/jni.h.
|
||||
AC_CHECK_FILE([$_JINC/jni.h],
|
||||
[JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JINC"],
|
||||
[_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||
AC_CHECK_FILE([$_JTOPDIR/include/jni.h],
|
||||
[JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include"],
|
||||
AC_MSG_ERROR([cannot find JDK header files]))
|
||||
])
|
||||
|
||||
# get the likely subdirectories for system specific java includes
|
||||
case "$host_os" in
|
||||
bsdi*) _JNI_INC_SUBDIRS="bsdos";;
|
||||
freebsd*) _JNI_INC_SUBDIRS="freebsd";;
|
||||
darwin*) _JNI_INC_SUBDIRS="darwin";;
|
||||
linux*) _JNI_INC_SUBDIRS="linux genunix";;
|
||||
osf*) _JNI_INC_SUBDIRS="alpha";;
|
||||
solaris*) _JNI_INC_SUBDIRS="solaris";;
|
||||
mingw*) _JNI_INC_SUBDIRS="win32";;
|
||||
cygwin*) _JNI_INC_SUBDIRS="win32";;
|
||||
*) _JNI_INC_SUBDIRS="genunix";;
|
||||
esac
|
||||
|
||||
# add any subdirectories that are present
|
||||
for JINCSUBDIR in $_JNI_INC_SUBDIRS
|
||||
do
|
||||
if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
|
||||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
|
||||
fi
|
||||
done
|
||||
])
|
||||
|
||||
# _ACJNI_FOLLOW_SYMLINKS <path>
|
||||
# Follows symbolic links on <path>,
|
||||
# finally setting variable _ACJNI_FOLLOWED
|
||||
# ----------------------------------------
|
||||
AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
|
||||
# find the include directory relative to the javac executable
|
||||
_cur="$1"
|
||||
while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
|
||||
AC_MSG_CHECKING([symlink for $_cur])
|
||||
_slink=`ls -ld "$_cur" | sed 's/.* -> //'`
|
||||
case "$_slink" in
|
||||
/*) _cur="$_slink";;
|
||||
# 'X' avoids triggering unwanted echo options.
|
||||
*) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
|
||||
esac
|
||||
AC_MSG_RESULT([$_cur])
|
||||
done
|
||||
_ACJNI_FOLLOWED="$_cur"
|
||||
])# _ACJNI
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,437 @@
|
|||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 8 ltoptions.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
|
||||
|
||||
|
||||
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ------------------------------------------
|
||||
m4_define([_LT_MANGLE_OPTION],
|
||||
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ---------------------------------------
|
||||
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
|
||||
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
|
||||
# saved as a flag.
|
||||
m4_define([_LT_SET_OPTION],
|
||||
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
|
||||
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
[m4_warning([Unknown $1 option '$2'])])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
|
||||
# ------------------------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
m4_define([_LT_IF_OPTION],
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
|
||||
|
||||
|
||||
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
|
||||
# -------------------------------------------------------
|
||||
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
|
||||
# are set.
|
||||
m4_define([_LT_UNLESS_OPTIONS],
|
||||
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
|
||||
[m4_define([$0_found])])])[]dnl
|
||||
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
|
||||
])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
|
||||
# ----------------------------------------
|
||||
# OPTION-LIST is a space-separated list of Libtool options associated
|
||||
# with MACRO-NAME. If any OPTION has a matching handler declared with
|
||||
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
|
||||
# the unknown option and exit.
|
||||
m4_defun([_LT_SET_OPTIONS],
|
||||
[# Set options
|
||||
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[_LT_SET_OPTION([$1], _LT_Option)])
|
||||
|
||||
m4_if([$1],[LT_INIT],[
|
||||
dnl
|
||||
dnl Simply set some default values (i.e off) if boolean options were not
|
||||
dnl specified:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
|
||||
])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
|
||||
])
|
||||
dnl
|
||||
dnl If no reference was made to various pairs of opposing options, then
|
||||
dnl we run the default mode handler for the pair. For example, if neither
|
||||
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
|
||||
dnl archives by default:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
|
||||
[_LT_ENABLE_FAST_INSTALL])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
|
||||
[_LT_WITH_AIX_SONAME([aix])])
|
||||
])
|
||||
])# _LT_SET_OPTIONS
|
||||
|
||||
|
||||
## --------------------------------- ##
|
||||
## Macros to handle LT_INIT options. ##
|
||||
## --------------------------------- ##
|
||||
|
||||
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
|
||||
# -----------------------------------------
|
||||
m4_define([_LT_MANGLE_DEFUN],
|
||||
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
|
||||
# -----------------------------------------------
|
||||
m4_define([LT_OPTION_DEFINE],
|
||||
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
|
||||
])# LT_OPTION_DEFINE
|
||||
|
||||
|
||||
# dlopen
|
||||
# ------
|
||||
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_DLOPEN],
|
||||
[_LT_SET_OPTION([LT_INIT], [dlopen])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'dlopen' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
|
||||
|
||||
|
||||
# win32-dll
|
||||
# ---------
|
||||
# Declare package support for building win32 dll's.
|
||||
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
|
||||
[enable_win32_dll=yes
|
||||
|
||||
case $host in
|
||||
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
|
||||
AC_CHECK_TOOL(AS, as, false)
|
||||
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
|
||||
AC_CHECK_TOOL(OBJDUMP, objdump, false)
|
||||
;;
|
||||
esac
|
||||
|
||||
test -z "$AS" && AS=as
|
||||
_LT_DECL([], [AS], [1], [Assembler program])dnl
|
||||
|
||||
test -z "$DLLTOOL" && DLLTOOL=dlltool
|
||||
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
|
||||
|
||||
test -z "$OBJDUMP" && OBJDUMP=objdump
|
||||
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
|
||||
])# win32-dll
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
|
||||
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
||||
_LT_SET_OPTION([LT_INIT], [win32-dll])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'win32-dll' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
|
||||
|
||||
|
||||
# _LT_ENABLE_SHARED([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-shared flag, and supports the 'shared' and
|
||||
# 'disable-shared' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_SHARED],
|
||||
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([shared],
|
||||
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
|
||||
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_shared=yes ;;
|
||||
no) enable_shared=no ;;
|
||||
*)
|
||||
enable_shared=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_shared=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
|
||||
|
||||
_LT_DECL([build_libtool_libs], [enable_shared], [0],
|
||||
[Whether or not to build shared libraries])
|
||||
])# _LT_ENABLE_SHARED
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-shared])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
|
||||
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_STATIC([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-static flag, and support the 'static' and
|
||||
# 'disable-static' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_STATIC],
|
||||
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([static],
|
||||
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
|
||||
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_static=yes ;;
|
||||
no) enable_static=no ;;
|
||||
*)
|
||||
enable_static=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_static=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
|
||||
|
||||
_LT_DECL([build_old_libs], [enable_static], [0],
|
||||
[Whether or not to build static libraries])
|
||||
])# _LT_ENABLE_STATIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-static])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
|
||||
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --enable-fast-install flag, and support the 'fast-install'
|
||||
# and 'disable-fast-install' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_FAST_INSTALL],
|
||||
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([fast-install],
|
||||
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
|
||||
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_fast_install=yes ;;
|
||||
no) enable_fast_install=no ;;
|
||||
*)
|
||||
enable_fast_install=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_fast_install=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
|
||||
|
||||
_LT_DECL([fast_install], [enable_fast_install], [0],
|
||||
[Whether or not to optimize for fast installation])dnl
|
||||
])# _LT_ENABLE_FAST_INSTALL
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
|
||||
|
||||
# Old names:
|
||||
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the 'fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the 'disable-fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
|
||||
|
||||
|
||||
# _LT_WITH_AIX_SONAME([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
|
||||
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
|
||||
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
|
||||
m4_define([_LT_WITH_AIX_SONAME],
|
||||
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
|
||||
shared_archive_member_spec=
|
||||
case $host,$enable_shared in
|
||||
power*-*-aix[[5-9]]*,yes)
|
||||
AC_MSG_CHECKING([which variant of shared library versioning to provide])
|
||||
AC_ARG_WITH([aix-soname],
|
||||
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
|
||||
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
|
||||
[case $withval in
|
||||
aix|svr4|both)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
|
||||
;;
|
||||
esac
|
||||
lt_cv_with_aix_soname=$with_aix_soname],
|
||||
[AC_CACHE_VAL([lt_cv_with_aix_soname],
|
||||
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
|
||||
with_aix_soname=$lt_cv_with_aix_soname])
|
||||
AC_MSG_RESULT([$with_aix_soname])
|
||||
if test aix != "$with_aix_soname"; then
|
||||
# For the AIX way of multilib, we name the shared archive member
|
||||
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
|
||||
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
|
||||
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
|
||||
# the AIX toolchain works better with OBJECT_MODE set (default 32).
|
||||
if test 64 = "${OBJECT_MODE-32}"; then
|
||||
shared_archive_member_spec=shr_64
|
||||
else
|
||||
shared_archive_member_spec=shr
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
with_aix_soname=aix
|
||||
;;
|
||||
esac
|
||||
|
||||
_LT_DECL([], [shared_archive_member_spec], [0],
|
||||
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
|
||||
])# _LT_WITH_AIX_SONAME
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
|
||||
|
||||
|
||||
# _LT_WITH_PIC([MODE])
|
||||
# --------------------
|
||||
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
|
||||
# LT_INIT options.
|
||||
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
|
||||
m4_define([_LT_WITH_PIC],
|
||||
[AC_ARG_WITH([pic],
|
||||
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
|
||||
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
|
||||
[lt_p=${PACKAGE-default}
|
||||
case $withval in
|
||||
yes|no) pic_mode=$withval ;;
|
||||
*)
|
||||
pic_mode=default
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for lt_pkg in $withval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$lt_pkg" = "X$lt_p"; then
|
||||
pic_mode=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[pic_mode=m4_default([$1], [default])])
|
||||
|
||||
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
|
||||
])# _LT_WITH_PIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
|
||||
|
||||
# Old name:
|
||||
AU_DEFUN([AC_LIBTOOL_PICMODE],
|
||||
[_LT_SET_OPTION([LT_INIT], [pic-only])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'pic-only' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
|
||||
|
||||
## ----------------- ##
|
||||
## LTDL_INIT Options ##
|
||||
## ----------------- ##
|
||||
|
||||
m4_define([_LTDL_MODE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
|
||||
[m4_define([_LTDL_MODE], [nonrecursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
|
||||
[m4_define([_LTDL_MODE], [recursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
|
||||
[m4_define([_LTDL_MODE], [subproject])])
|
||||
|
||||
m4_define([_LTDL_TYPE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [installable],
|
||||
[m4_define([_LTDL_TYPE], [installable])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
|
||||
[m4_define([_LTDL_TYPE], [convenience])])
|
|
@ -0,0 +1,124 @@
|
|||
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 6 ltsugar.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
|
||||
|
||||
|
||||
# lt_join(SEP, ARG1, [ARG2...])
|
||||
# -----------------------------
|
||||
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
|
||||
# associated separator.
|
||||
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
|
||||
# versions in m4sugar had bugs.
|
||||
m4_define([lt_join],
|
||||
[m4_if([$#], [1], [],
|
||||
[$#], [2], [[$2]],
|
||||
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
m4_define([_lt_join],
|
||||
[m4_if([$#$2], [2], [],
|
||||
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
|
||||
|
||||
# lt_car(LIST)
|
||||
# lt_cdr(LIST)
|
||||
# ------------
|
||||
# Manipulate m4 lists.
|
||||
# These macros are necessary as long as will still need to support
|
||||
# Autoconf-2.59, which quotes differently.
|
||||
m4_define([lt_car], [[$1]])
|
||||
m4_define([lt_cdr],
|
||||
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
|
||||
[$#], 1, [],
|
||||
[m4_dquote(m4_shift($@))])])
|
||||
m4_define([lt_unquote], $1)
|
||||
|
||||
|
||||
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
|
||||
# ------------------------------------------
|
||||
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
|
||||
# Note that neither SEPARATOR nor STRING are expanded; they are appended
|
||||
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
|
||||
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
|
||||
# than defined and empty).
|
||||
#
|
||||
# This macro is needed until we can rely on Autoconf 2.62, since earlier
|
||||
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
|
||||
m4_define([lt_append],
|
||||
[m4_define([$1],
|
||||
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
|
||||
|
||||
|
||||
|
||||
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
|
||||
# ----------------------------------------------------------
|
||||
# Produce a SEP delimited list of all paired combinations of elements of
|
||||
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
|
||||
# has the form PREFIXmINFIXSUFFIXn.
|
||||
# Needed until we can rely on m4_combine added in Autoconf 2.62.
|
||||
m4_define([lt_combine],
|
||||
[m4_if(m4_eval([$# > 3]), [1],
|
||||
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
|
||||
[[m4_foreach([_Lt_prefix], [$2],
|
||||
[m4_foreach([_Lt_suffix],
|
||||
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
|
||||
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
|
||||
|
||||
|
||||
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
|
||||
# -----------------------------------------------------------------------
|
||||
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
|
||||
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
|
||||
m4_define([lt_if_append_uniq],
|
||||
[m4_ifdef([$1],
|
||||
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
|
||||
[lt_append([$1], [$2], [$3])$4],
|
||||
[$5])],
|
||||
[lt_append([$1], [$2], [$3])$4])])
|
||||
|
||||
|
||||
# lt_dict_add(DICT, KEY, VALUE)
|
||||
# -----------------------------
|
||||
m4_define([lt_dict_add],
|
||||
[m4_define([$1($2)], [$3])])
|
||||
|
||||
|
||||
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
|
||||
# --------------------------------------------
|
||||
m4_define([lt_dict_add_subkey],
|
||||
[m4_define([$1($2:$3)], [$4])])
|
||||
|
||||
|
||||
# lt_dict_fetch(DICT, KEY, [SUBKEY])
|
||||
# ----------------------------------
|
||||
m4_define([lt_dict_fetch],
|
||||
[m4_ifval([$3],
|
||||
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
|
||||
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
|
||||
|
||||
|
||||
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
|
||||
# -----------------------------------------------------------------
|
||||
m4_define([lt_if_dict_fetch],
|
||||
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
|
||||
[$5],
|
||||
[$6])])
|
||||
|
||||
|
||||
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
|
||||
# --------------------------------------------------------------
|
||||
m4_define([lt_dict_filter],
|
||||
[m4_if([$5], [], [],
|
||||
[lt_join(m4_quote(m4_default([$4], [[, ]])),
|
||||
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
|
||||
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
|
||||
])
|
|
@ -0,0 +1,23 @@
|
|||
# ltversion.m4 -- version numbers -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# @configure_input@
|
||||
|
||||
# serial 4179 ltversion.m4
|
||||
# This file is part of GNU Libtool
|
||||
|
||||
m4_define([LT_PACKAGE_VERSION], [2.4.6])
|
||||
m4_define([LT_PACKAGE_REVISION], [2.4.6])
|
||||
|
||||
AC_DEFUN([LTVERSION_VERSION],
|
||||
[macro_version='2.4.6'
|
||||
macro_revision='2.4.6'
|
||||
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
|
||||
_LT_DECL(, macro_revision, 0)
|
||||
])
|
|
@ -0,0 +1,99 @@
|
|||
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 5 lt~obsolete.m4
|
||||
|
||||
# These exist entirely to fool aclocal when bootstrapping libtool.
|
||||
#
|
||||
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
|
||||
# which have later been changed to m4_define as they aren't part of the
|
||||
# exported API, or moved to Autoconf or Automake where they belong.
|
||||
#
|
||||
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
|
||||
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
|
||||
# using a macro with the same name in our local m4/libtool.m4 it'll
|
||||
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
|
||||
# and doesn't know about Autoconf macros at all.)
|
||||
#
|
||||
# So we provide this file, which has a silly filename so it's always
|
||||
# included after everything else. This provides aclocal with the
|
||||
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
|
||||
# because those macros already exist, or will be overwritten later.
|
||||
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
|
||||
#
|
||||
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
|
||||
# Yes, that means every name once taken will need to remain here until
|
||||
# we give up compatibility with versions before 1.7, at which point
|
||||
# we need to keep only those names which we still refer to.
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
|
||||
|
||||
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
|
||||
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
|
||||
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
|
||||
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
|
||||
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
|
||||
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
|
||||
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
|
||||
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
|
||||
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
|
||||
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
|
||||
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
|
||||
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
|
||||
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
|
||||
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
|
||||
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
|
||||
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
|
||||
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
|
||||
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
|
||||
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
|
||||
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
|
||||
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
|
||||
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
|
||||
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
|
||||
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
|
||||
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
|
||||
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
|
||||
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
|
||||
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
|
||||
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
|
||||
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
|
||||
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
|
||||
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
|
||||
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
|
||||
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
|
||||
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
|
||||
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
|
|
@ -0,0 +1,577 @@
|
|||
/*
|
||||
* cli.c - stoken command-line interface
|
||||
*
|
||||
* Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "stoken.h"
|
||||
#include "securid.h"
|
||||
#include "sdtid.h"
|
||||
#include "stoken-internal.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static int plat_read_user_input(char *out, int max_len, int hide_chars)
|
||||
{
|
||||
/* TODO: Hide passwords */
|
||||
char *p;
|
||||
|
||||
fgets(out, max_len, stdin);
|
||||
p = strchr(out, '\n');
|
||||
if (p)
|
||||
*p = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void terminal_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int fork_and_wait(void)
|
||||
{
|
||||
/* TODO */
|
||||
die("Subprocess support is not yet implemented on Windows.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
#include <termios.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static struct termios oldtio;
|
||||
|
||||
static void stdin_echo(int enable_echo)
|
||||
{
|
||||
struct termios tio = oldtio;
|
||||
const int fd = 0;
|
||||
|
||||
if (!enable_echo) {
|
||||
/* ripped from busybox bb_ask() */
|
||||
tcflush(fd, TCIFLUSH);
|
||||
tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL);
|
||||
tcsetattr(fd, TCSANOW, &tio);
|
||||
} else
|
||||
tcsetattr(fd, TCSANOW, &oldtio);
|
||||
}
|
||||
|
||||
static int plat_read_user_input(char *out, int max_len, int hide_chars)
|
||||
{
|
||||
char *p;
|
||||
int ret = 0;
|
||||
|
||||
stdin_echo(!hide_chars);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
if (fgets(out, max_len, stdin) == NULL) {
|
||||
*out = 0;
|
||||
goto done;
|
||||
}
|
||||
p = strchr(out, '\n');
|
||||
if (p)
|
||||
*p = 0;
|
||||
ret = strlen(out);
|
||||
|
||||
done:
|
||||
stdin_echo(1);
|
||||
if (hide_chars && isatty(fileno(stdin)))
|
||||
puts("");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void restore_tio(int sig)
|
||||
{
|
||||
stdin_echo(1);
|
||||
puts("");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void terminal_init(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
const int fd = 0;
|
||||
|
||||
/* restore a sane terminal state if interrupted */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = &restore_tio;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
|
||||
tcgetattr(fd, &oldtio);
|
||||
}
|
||||
|
||||
static int fork_and_wait(void)
|
||||
{
|
||||
pid_t child = fork();
|
||||
|
||||
if (child < 0)
|
||||
die("can't fork\n");
|
||||
else if (child == 0)
|
||||
return 0;
|
||||
else if (child > 0) {
|
||||
int rv;
|
||||
wait(&rv);
|
||||
if (!WIFEXITED(rv) || WEXITSTATUS(rv))
|
||||
exit(1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static int read_user_input(char *out, int max_len, int hide_chars)
|
||||
{
|
||||
static int first = 1;
|
||||
|
||||
if (opt_stdin) {
|
||||
if (!first) {
|
||||
prompt("\n");
|
||||
die("error: --stdin only allows one prompt\n");
|
||||
}
|
||||
first = 0;
|
||||
return plat_read_user_input(out, max_len, hide_chars);
|
||||
}
|
||||
|
||||
if (opt_batch) {
|
||||
prompt("\n");
|
||||
die("error: --batch mode specified but command-line input is requested\n");
|
||||
}
|
||||
|
||||
return plat_read_user_input(out, max_len, hide_chars);
|
||||
}
|
||||
|
||||
static void print_token_info_line(const char *key, const char *value)
|
||||
{
|
||||
/* require --seed to show anything sensitive */
|
||||
if (strcasestr(key, "seed") && !opt_seed)
|
||||
return;
|
||||
printf("%-24s: %s\n", key, value);
|
||||
}
|
||||
|
||||
static time_t adjusted_time(struct securid_token *t)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
long new_time;
|
||||
|
||||
if (opt_next && opt_use_time)
|
||||
die("error: --use-time and --next are mutually exclusive\n");
|
||||
if (opt_next)
|
||||
return now + securid_token_interval(t);
|
||||
|
||||
if (!opt_use_time)
|
||||
return now;
|
||||
else if (sscanf(opt_use_time, "+%ld", &new_time) == 1)
|
||||
return now + new_time;
|
||||
else if (sscanf(opt_use_time, "-%ld", &new_time) == 1)
|
||||
return now - new_time;
|
||||
else if (sscanf(opt_use_time, "%ld", &new_time) == 1)
|
||||
return new_time;
|
||||
|
||||
die("error: invalid --use-time argument\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void request_devid(struct securid_token *t, char *devid)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (opt_devid) {
|
||||
if (securid_check_devid(t, opt_devid) == ERR_NONE) {
|
||||
xstrncpy(devid, opt_devid, BUFLEN);
|
||||
return;
|
||||
}
|
||||
warn("warning: --devid parameter is incorrect\n");
|
||||
} else {
|
||||
const struct stoken_guid *glist = stoken_get_guid_list();
|
||||
for (i = 0; glist[i].tag != NULL; i++) {
|
||||
if (securid_check_devid(t, glist[i].guid) == ERR_NONE) {
|
||||
prompt("Using class GUID for %s; use --devid to override\n",
|
||||
glist[i].long_name);
|
||||
strncpy(devid, glist[i].guid, BUFLEN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prompt("This token is bound to a specific device.\n");
|
||||
for (i = 0; ; i++) {
|
||||
prompt("Enter device ID from the RSA 'About' screen: ");
|
||||
if (read_user_input(devid, BUFLEN, 0) == 0)
|
||||
continue;
|
||||
|
||||
if (securid_check_devid(t, devid) == ERR_NONE)
|
||||
return;
|
||||
if (i == 2)
|
||||
die("error: invalid device ID\n");
|
||||
|
||||
prompt("Device ID does not match the token.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void request_pass(const char *prompt_msg, struct securid_token *t,
|
||||
char *pass, char *devid)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
if (opt_password) {
|
||||
rc = securid_decrypt_seed(t, opt_password, devid);
|
||||
if (rc != ERR_DECRYPT_FAILED && rc != ERR_BAD_PASSWORD) {
|
||||
xstrncpy(pass, opt_password, BUFLEN);
|
||||
return;
|
||||
}
|
||||
warn("warning: --password parameter is incorrect\n");
|
||||
}
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
prompt(prompt_msg);
|
||||
if (read_user_input(pass, BUFLEN, 1) == 0)
|
||||
continue;
|
||||
|
||||
rc = securid_decrypt_seed(t, pass, devid);
|
||||
if (rc == ERR_DECRYPT_FAILED) {
|
||||
if (i == 2)
|
||||
die("error: invalid password\n");
|
||||
warn("Bad password.\n");
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void request_new_pass(char *pass)
|
||||
{
|
||||
char confirm_pass[BUFLEN];
|
||||
int len;
|
||||
|
||||
if (opt_new_password) {
|
||||
len = strlen(opt_new_password);
|
||||
if (len > MAX_PASS)
|
||||
die("error: new password is too long\n");
|
||||
xstrncpy(pass, opt_new_password, BUFLEN);
|
||||
} else {
|
||||
prompt("Enter new password: ");
|
||||
len = read_user_input(pass, BUFLEN, 1);
|
||||
prompt("Confirm new password: ");
|
||||
read_user_input(confirm_pass, BUFLEN, 1);
|
||||
|
||||
if (len > MAX_PASS)
|
||||
die("error: new password is too long\n");
|
||||
|
||||
if (strcmp(pass, confirm_pass) != 0)
|
||||
die("error: passwords do not match\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void request_pin(const char *prompt_msg, char *pin)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
if (opt_pin) {
|
||||
rc = securid_pin_format_ok(opt_pin);
|
||||
if (rc == ERR_BAD_LEN)
|
||||
warn("warning: bad --pin argument length, ignoring\n");
|
||||
else if (rc == ERR_GENERAL)
|
||||
warn("warning: --pin argument is not numeric, ignoring\n");
|
||||
else {
|
||||
xstrncpy(pin, opt_pin, BUFLEN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
prompt(prompt_msg);
|
||||
read_user_input(pin, BUFLEN, 1);
|
||||
rc = securid_pin_format_ok(pin);
|
||||
|
||||
if (rc == ERR_NONE)
|
||||
break;
|
||||
if (i == 2)
|
||||
die("error: invalid PIN\n");
|
||||
|
||||
if (rc == ERR_BAD_LEN)
|
||||
warn("PIN must be %d-%d digits. Use '0000' for no PIN.\n",
|
||||
MIN_PIN, MAX_PIN);
|
||||
else
|
||||
warn("PIN can only contain digits.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void unlock_token(struct securid_token *t, int get_pin, char **ret_pass)
|
||||
{
|
||||
char devid[BUFLEN] = { 0 }, pass[BUFLEN] = { 0 }, pin[BUFLEN];
|
||||
int rc;
|
||||
|
||||
if (securid_devid_required(t))
|
||||
request_devid(t, devid);
|
||||
|
||||
if (securid_pass_required(t))
|
||||
request_pass("Enter password to decrypt token: ",
|
||||
t, pass, devid);
|
||||
|
||||
rc = securid_decrypt_seed(t, pass, devid);
|
||||
if (rc != ERR_NONE)
|
||||
die("error: can't decrypt token: %s\n", stoken_errstr[rc]);
|
||||
|
||||
if (t->enc_pin_str)
|
||||
if (securid_decrypt_pin(t->enc_pin_str, pass, t->pin) !=
|
||||
ERR_NONE)
|
||||
warn("warning: can't decrypt PIN\n");
|
||||
|
||||
if (ret_pass && strlen(pass))
|
||||
*ret_pass = xstrdup(pass);
|
||||
|
||||
/* always allow --pin to override .stokenrc */
|
||||
if (get_pin && securid_pin_required(t) &&
|
||||
(!strlen(t->pin) || opt_pin)) {
|
||||
request_pin("Enter PIN:", pin);
|
||||
xstrncpy(t->pin, pin, MAX_PIN + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_formatted(const char *buf)
|
||||
{
|
||||
char *formatted;
|
||||
|
||||
formatted = format_token(buf);
|
||||
puts(formatted);
|
||||
free(formatted);
|
||||
}
|
||||
|
||||
static void display_qr(const char *filename)
|
||||
{
|
||||
const char *programs[] = {
|
||||
/*
|
||||
* I'd like to include xdg-open here, but it insists on
|
||||
* opening the file in the background, which races with the
|
||||
* temporary file cleanup.
|
||||
*/
|
||||
"display", /* ImageMagick */
|
||||
"eog", /* Eye of GNOME */
|
||||
"gwenview", /* KDE viewer */
|
||||
"ristretto", /* Xfce */
|
||||
NULL,
|
||||
};
|
||||
const char **p, *user;
|
||||
|
||||
if (fork_and_wait() != 0)
|
||||
return;
|
||||
|
||||
user = getenv("QR_VIEWER");
|
||||
if (user) {
|
||||
execlp(user, user, filename, NULL);
|
||||
die("unable to execute '%s'\n", user);
|
||||
}
|
||||
|
||||
for (p = programs; *p; p++)
|
||||
execlp(*p, *p, filename, NULL);
|
||||
|
||||
die("can't find a suitable image viewer; try setting $QR_VIEWER\n");
|
||||
}
|
||||
|
||||
static void __export_qr(const char *filename, const char *token)
|
||||
{
|
||||
if (fork_and_wait() != 0)
|
||||
return;
|
||||
execlp("qrencode", "qrencode", "-l", "H", "-o", filename,
|
||||
token, NULL);
|
||||
die("can't exec qrencode (is it in your PATH?)\n");
|
||||
}
|
||||
|
||||
static void export_qr(const char *filename, const char *token)
|
||||
{
|
||||
char *formatted;
|
||||
|
||||
if (opt_blocks) {
|
||||
warn("warning: --blocks is invalid in QR mode; using --android\n");
|
||||
opt_android = 1;
|
||||
opt_blocks = 0;
|
||||
}
|
||||
|
||||
if (!(opt_android || opt_iphone || opt_v3))
|
||||
opt_android = 1;
|
||||
|
||||
formatted = format_token(token);
|
||||
|
||||
if (filename)
|
||||
__export_qr(filename, formatted);
|
||||
else {
|
||||
char fname[64];
|
||||
int fd;
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s/XXXXXX.png",
|
||||
getenv("TMPDIR") ? : "/tmp");
|
||||
fd = mkstemps(fname, 4);
|
||||
if (fd < 0)
|
||||
die("can't create temp file '%s'\n", fname);
|
||||
__export_qr(fname, formatted);
|
||||
display_qr(fname);
|
||||
unlink(fname);
|
||||
}
|
||||
free(formatted);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *cmd = parse_cmdline(argc, argv, NOT_GUI);
|
||||
int rc;
|
||||
char buf[BUFLEN];
|
||||
struct securid_token *t;
|
||||
|
||||
rc = common_init(cmd);
|
||||
if (rc != ERR_NONE)
|
||||
die("can't initialize: %s\n", stoken_errstr[rc]);
|
||||
|
||||
if (!strcmp(cmd, "issue")) {
|
||||
rc = sdtid_issue(opt_template, opt_new_password, opt_new_devid);
|
||||
if (rc != ERR_NONE)
|
||||
die("issue: error generating sdtid: %s\n",
|
||||
stoken_errstr[rc]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
t = current_token;
|
||||
if (!t)
|
||||
die("error: no token present. Use 'stoken import' to add one.\n");
|
||||
|
||||
terminal_init();
|
||||
|
||||
if (!strcmp(cmd, "tokencode")) {
|
||||
int days_left;
|
||||
|
||||
unlock_token(t, 1, NULL);
|
||||
|
||||
days_left = securid_check_exp(t, adjusted_time(t));
|
||||
if (days_left < 0 && !opt_force)
|
||||
die("error: token has expired; use --force to override\n");
|
||||
|
||||
securid_compute_tokencode(t, adjusted_time(t), buf);
|
||||
puts(buf);
|
||||
|
||||
if (days_left < 14 && !opt_force)
|
||||
warn("warning: token expires in %d day%s\n", days_left,
|
||||
days_left == 1 ? "" : "s");
|
||||
} else if (!strcmp(cmd, "import")) {
|
||||
char *pass;
|
||||
|
||||
unlock_token(t, 0, &pass);
|
||||
if (!opt_keep_password) {
|
||||
pass = xmalloc(BUFLEN);
|
||||
request_new_pass(pass);
|
||||
}
|
||||
|
||||
t->is_smartphone = 0;
|
||||
securid_encode_token(t, pass, opt_new_devid, 2, buf);
|
||||
rc = write_token_and_pin(buf, NULL, pass);
|
||||
if (rc != ERR_NONE)
|
||||
die("rcfile: error writing new token: %s\n",
|
||||
stoken_errstr[rc]);
|
||||
} else if (!strcmp(cmd, "export")) {
|
||||
char *pass;
|
||||
|
||||
unlock_token(t, 0, &pass);
|
||||
if (opt_new_password)
|
||||
pass = opt_new_password;
|
||||
else if (!opt_keep_password)
|
||||
pass = NULL;
|
||||
|
||||
if (!opt_sdtid) {
|
||||
t->is_smartphone = opt_iphone || opt_android ||
|
||||
opt_v3 || opt_show_qr || opt_qr;
|
||||
securid_encode_token(t, pass, opt_new_devid,
|
||||
opt_v3 ? 3 : 2, buf);
|
||||
|
||||
if (opt_show_qr || opt_qr)
|
||||
export_qr(opt_show_qr ? NULL : opt_qr, buf);
|
||||
else
|
||||
print_formatted(buf);
|
||||
} else {
|
||||
rc = sdtid_export(opt_template, t, pass, opt_new_devid);
|
||||
if (rc != ERR_NONE)
|
||||
die("export: error writing sdtid: %s\n",
|
||||
stoken_errstr[rc]);
|
||||
}
|
||||
} else if (!strcmp(cmd, "show")) {
|
||||
unlock_token(t, 0, NULL);
|
||||
securid_token_info(t, &print_token_info_line);
|
||||
} else if (!strcmp(cmd, "setpin")) {
|
||||
char *pass = NULL, pin[BUFLEN], confirm_pin[BUFLEN];
|
||||
int len;
|
||||
|
||||
if (opt_file || opt_token)
|
||||
die("error: setpin only operates on the rcfile token\n");
|
||||
|
||||
unlock_token(t, 0, &pass);
|
||||
|
||||
if (opt_new_pin) {
|
||||
if (securid_pin_format_ok(opt_new_pin) != ERR_NONE)
|
||||
die("error: invalid --new-pin format\n");
|
||||
xstrncpy(pin, opt_new_pin, BUFLEN);
|
||||
len = strlen(pin);
|
||||
} else {
|
||||
prompt("Enter new PIN: ");
|
||||
len = read_user_input(pin, BUFLEN, 1);
|
||||
if (len > 0 && securid_pin_format_ok(pin) != ERR_NONE)
|
||||
die("error: PIN must be 4-8 digits\n");
|
||||
|
||||
prompt("Confirm new PIN: ");
|
||||
read_user_input(confirm_pin, BUFLEN, 1);
|
||||
if (strcmp(pin, confirm_pin) != 0)
|
||||
die("error: PINs do not match\n");
|
||||
}
|
||||
|
||||
securid_encode_token(t, pass, NULL, 2, buf);
|
||||
rc = write_token_and_pin(buf, len ? pin : NULL, pass);
|
||||
free(pass);
|
||||
|
||||
if (rc != ERR_NONE)
|
||||
die("error: can't set PIN: %s\n", stoken_errstr[rc]);
|
||||
} else if (!strcmp(cmd, "setpass")) {
|
||||
char pass[BUFLEN];
|
||||
|
||||
unlock_token(t, 0, NULL);
|
||||
request_new_pass(pass);
|
||||
securid_encode_token(t, pass, NULL, 2, buf);
|
||||
|
||||
/* just print to stdout if it didn't come from the rcfile */
|
||||
if (opt_file || opt_token)
|
||||
print_formatted(buf);
|
||||
else {
|
||||
rc = write_token_and_pin(buf,
|
||||
strlen(t->pin) ? t->pin : NULL,
|
||||
strlen(pass) ? pass : NULL);
|
||||
if (rc != ERR_NONE)
|
||||
die("error: can't set password: %s\n",
|
||||
stoken_errstr[rc]);
|
||||
}
|
||||
} else
|
||||
die("error: invalid command '%s'\n", cmd);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,481 @@
|
|||
/*
|
||||
* common.c - Common functions for stoken and stoken-gui
|
||||
*
|
||||
* Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_MLOCKALL
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "securid.h"
|
||||
#include "stoken.h"
|
||||
#include "stoken-internal.h"
|
||||
|
||||
/* globals - shared with cli.c or gui.c */
|
||||
|
||||
int opt_random, opt_keep_password, opt_blocks, opt_iphone, opt_android,
|
||||
opt_v3, opt_show_qr, opt_seed, opt_sdtid, opt_small, opt_next;
|
||||
int opt_debug, opt_version, opt_help, opt_batch, opt_force, opt_stdin;
|
||||
char *opt_rcfile, *opt_file, *opt_token, *opt_devid, *opt_password,
|
||||
*opt_pin, *opt_use_time, *opt_new_password, *opt_new_devid,
|
||||
*opt_new_pin, *opt_template, *opt_qr;
|
||||
struct securid_token *current_token;
|
||||
|
||||
static int debug_level;
|
||||
static struct stoken_cfg *cfg;
|
||||
|
||||
void prompt(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
if (!opt_stdin)
|
||||
vfprintf(stdout, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void warn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fflush(stdout);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void dbg(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (!debug_level)
|
||||
return;
|
||||
va_start(ap, fmt);
|
||||
fflush(stdout);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void die(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fflush(stdout);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *xstrdup(const char *s)
|
||||
{
|
||||
char *ret = strdup(s);
|
||||
if (!ret)
|
||||
die("out of memory\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *xconcat(const char *s1, const char *s2)
|
||||
{
|
||||
char *ret = xmalloc(strlen(s1) + strlen(s2) + 1);
|
||||
strcpy(ret, s1);
|
||||
strcat(ret, s2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xstrncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
strncpy(dest, src, n);
|
||||
dest[n - 1] = 0;
|
||||
}
|
||||
|
||||
void *xmalloc(size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
if (!ret)
|
||||
die("out of memory\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *xzalloc(size_t size)
|
||||
{
|
||||
void *ret = xmalloc(size);
|
||||
memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum {
|
||||
OPT_DEVID = 1,
|
||||
OPT_USE_TIME,
|
||||
OPT_NEW_PASSWORD,
|
||||
OPT_NEW_DEVID,
|
||||
OPT_NEW_PIN,
|
||||
OPT_TEMPLATE,
|
||||
OPT_QR,
|
||||
};
|
||||
|
||||
static const struct option long_opts[] = {
|
||||
/* global: token sources */
|
||||
{ "rcfile", 1, NULL, 'r' },
|
||||
{ "file", 1, NULL, 'i' },
|
||||
{ "token", 1, NULL, 't' },
|
||||
{ "random", 0, &opt_random, 1, },
|
||||
|
||||
/* global: secrets used to decrypt/use a seed */
|
||||
{ "devid", 1, NULL, OPT_DEVID },
|
||||
{ "password", 1, NULL, 'p' },
|
||||
{ "pin", 1, NULL, 'n' },
|
||||
|
||||
/* GUI: use smaller window */
|
||||
{ "small", 0, &opt_small, 1 },
|
||||
|
||||
/* global: misc/debug */
|
||||
{ "debug", 0, NULL, 'd' },
|
||||
{ "version", 0, NULL, 'v' },
|
||||
{ "force", 0, NULL, 'f' },
|
||||
{ "use-time", 1, NULL, OPT_USE_TIME },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
|
||||
/* all remaining options are for CLI only */
|
||||
#define FINAL_GUI_OPTION "help"
|
||||
|
||||
{ "batch", 0, NULL, 'b' },
|
||||
|
||||
/* used for tokencode generation */
|
||||
{ "next", 0, &opt_next, 1 },
|
||||
|
||||
/* these are mostly for exporting/issuing tokens */
|
||||
{ "new-password", 1, NULL, OPT_NEW_PASSWORD },
|
||||
{ "new-devid", 1, NULL, OPT_NEW_DEVID },
|
||||
{ "new-pin", 1, NULL, OPT_NEW_PIN },
|
||||
{ "template", 1, NULL, OPT_TEMPLATE },
|
||||
{ "keep-password", 0, &opt_keep_password, 1 },
|
||||
{ "blocks", 0, &opt_blocks, 1 },
|
||||
{ "iphone", 0, &opt_iphone, 1 },
|
||||
{ "android", 0, &opt_android, 1 },
|
||||
{ "v3", 0, &opt_v3, 1 },
|
||||
{ "sdtid", 0, &opt_sdtid, 1 },
|
||||
{ "xml", 0, &opt_sdtid, 1 },
|
||||
{ "qr", 1, NULL, OPT_QR },
|
||||
{ "show-qr", 0, &opt_show_qr, 1 },
|
||||
{ "seed", 0, &opt_seed, 1 },
|
||||
{ "stdin", 0, NULL, 's' },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
static void usage_common(void)
|
||||
{
|
||||
puts("Alternate seed sources:");
|
||||
puts("");
|
||||
puts(" --rcfile=<alt_rcfile>");
|
||||
puts(" --token=<token_string>");
|
||||
puts(" --file=<token_file>");
|
||||
puts(" --random");
|
||||
puts("");
|
||||
puts("See the stoken(1) man page for additional information.");
|
||||
}
|
||||
|
||||
static void usage_gui(void)
|
||||
{
|
||||
puts("usage: stoken-gui [ <options> ]");
|
||||
puts("");
|
||||
usage_common();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void usage_cli(void)
|
||||
{
|
||||
puts("usage: stoken <cmd> [ <options> ]");
|
||||
puts("");
|
||||
puts("Common operations:");
|
||||
puts("");
|
||||
puts(" stoken [ tokencode ] [ --stdin ]");
|
||||
puts(" stoken import { --token=<token_string> | --file=<token_file> } [ --force ]");
|
||||
puts(" stoken setpass");
|
||||
puts(" stoken setpin");
|
||||
puts("");
|
||||
puts("Other commands:");
|
||||
puts("");
|
||||
puts(" stoken show [ --seed ]");
|
||||
puts(" stoken export [ { --blocks | --iphone | --android | --v3 | --sdtid |");
|
||||
puts(" --qr=<file> | --show-qr } ]");
|
||||
puts(" stoken issue [ --template=<sdtid_skeleton> ]");
|
||||
puts("");
|
||||
usage_common();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void show_version(void)
|
||||
{
|
||||
puts(PACKAGE_STRING " - software token for Linux/UNIX systems");
|
||||
puts("Copyright (C) 2014 Kevin Cernekee <cernekee@gmail.com>");
|
||||
puts("");
|
||||
puts("This is free software with ABSOLUTELY NO WARRANTY.");
|
||||
puts("For details see the COPYING.LIB file in the source distribution.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
char *parse_cmdline(int argc, char **argv, int is_gui)
|
||||
{
|
||||
int ret, longindex = 0, last_gui_opt = 0;
|
||||
const struct option *opt = long_opts;
|
||||
char *cmd = NULL;
|
||||
|
||||
for (; strcmp(opt->name, FINAL_GUI_OPTION); last_gui_opt++, opt++)
|
||||
;
|
||||
|
||||
while (1) {
|
||||
ret = getopt_long(argc, argv, "r:i:t:p:n:dvhbfs",
|
||||
long_opts, &longindex);
|
||||
if (ret == -1)
|
||||
break;
|
||||
|
||||
if (is_gui && longindex > last_gui_opt)
|
||||
die("error: --%s is not valid in GUI mode\n",
|
||||
long_opts[longindex].name);
|
||||
|
||||
switch (ret) {
|
||||
case 'r': opt_rcfile = optarg; break;
|
||||
case 'i': opt_file = optarg; break;
|
||||
case 't': opt_token = optarg; break;
|
||||
case 'p': opt_password = optarg; break;
|
||||
case 'n': opt_pin = optarg; break;
|
||||
case 'd': opt_debug = 1; break;
|
||||
case 'v': opt_version = 1; break;
|
||||
case 'h': opt_help = 1; break;
|
||||
case 'b': opt_batch = 1; break;
|
||||
case 'f': opt_force = 1; break;
|
||||
case 's': opt_stdin = 1; break;
|
||||
case OPT_DEVID: opt_devid = optarg; break;
|
||||
case OPT_USE_TIME: opt_use_time = optarg; break;
|
||||
case OPT_NEW_PASSWORD: opt_new_password = optarg; break;
|
||||
case OPT_NEW_DEVID: opt_new_devid = optarg; break;
|
||||
case OPT_NEW_PIN: opt_new_pin = optarg; break;
|
||||
case OPT_TEMPLATE: opt_template = optarg; break;
|
||||
case OPT_QR: opt_qr = optarg; break;
|
||||
case 0: break;
|
||||
default: opt_help = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_gui && optind == argc - 1)
|
||||
cmd = argv[optind];
|
||||
else if (optind == argc)
|
||||
cmd = xstrdup("tokencode"); /* default command */
|
||||
else
|
||||
warn("error: too many command-line arguments\n");
|
||||
|
||||
if (!cmd || !strcmp(cmd, "help") || opt_help) {
|
||||
if (is_gui)
|
||||
usage_gui();
|
||||
else
|
||||
usage_cli();
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, "version") || opt_version)
|
||||
show_version();
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static int read_token_from_file(char *filename, struct securid_token *t)
|
||||
{
|
||||
char buf[65536], *p;
|
||||
int rc = ERR_BAD_LEN;
|
||||
FILE *f;
|
||||
size_t len;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL)
|
||||
return ERR_FILE_READ;
|
||||
|
||||
len = fread(buf, 1, sizeof(buf) - 1, f);
|
||||
if (ferror(f))
|
||||
len = 0;
|
||||
fclose(f);
|
||||
|
||||
if (len == 0)
|
||||
return ERR_FILE_READ;
|
||||
buf[len] = 0;
|
||||
|
||||
for (p = buf; *p; ) {
|
||||
rc = __stoken_parse_and_decode_token(p, t, 1);
|
||||
|
||||
/*
|
||||
* keep checking more lines until we find something that
|
||||
* looks like a token
|
||||
*/
|
||||
if (rc != ERR_GENERAL)
|
||||
break;
|
||||
|
||||
p = strchr(p, '\n');
|
||||
if (!p)
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int decode_rc_token(struct stoken_cfg *cfg, struct securid_token *t)
|
||||
{
|
||||
int rc = securid_decode_token(cfg->rc_token, t);
|
||||
|
||||
if (rc != ERR_NONE) {
|
||||
warn("rcfile: token data is garbled, ignoring\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (cfg->rc_pin) {
|
||||
if (t->flags & FL_PASSPROT)
|
||||
t->enc_pin_str = xstrdup(cfg->rc_pin);
|
||||
else {
|
||||
if (securid_pin_format_ok(cfg->rc_pin) == ERR_NONE)
|
||||
xstrncpy(t->pin, cfg->rc_pin, MAX_PIN + 1);
|
||||
else
|
||||
warn("rcfile: invalid PIN format\n");
|
||||
}
|
||||
}
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
int common_init(char *cmd)
|
||||
{
|
||||
int rc;
|
||||
struct securid_token *t;
|
||||
int is_import = !strcmp(cmd, "import");
|
||||
|
||||
/*
|
||||
* we don't actually scrub memory, but at least try to keep the seeds
|
||||
* from being swapped out to disk
|
||||
*/
|
||||
#ifdef HAVE_MLOCKALL
|
||||
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||
#endif
|
||||
|
||||
stc_standalone_init();
|
||||
|
||||
cfg = xzalloc(sizeof(*cfg));
|
||||
if (__stoken_read_rcfile(opt_rcfile, cfg,
|
||||
is_import ? &dbg : &warn) != ERR_NONE)
|
||||
__stoken_zap_rcfile_data(cfg);
|
||||
|
||||
/* accept a token from the command line, or fall back to the rcfile */
|
||||
do {
|
||||
t = xzalloc(sizeof(struct securid_token));
|
||||
|
||||
if (opt_token) {
|
||||
rc = __stoken_parse_and_decode_token(opt_token, t, 1);
|
||||
if (rc != ERR_NONE)
|
||||
die("error: --token string is garbled: %s\n",
|
||||
stoken_errstr[rc]);
|
||||
current_token = t;
|
||||
break;
|
||||
}
|
||||
if (opt_file) {
|
||||
rc = read_token_from_file(opt_file, t);
|
||||
if (rc == ERR_MULTIPLE_TOKENS)
|
||||
die("error: multiple tokens found; use 'stoken split' to create separate files\n");
|
||||
else if (rc != ERR_NONE)
|
||||
die("error: no valid token in file '%s': %s\n",
|
||||
opt_file, stoken_errstr[rc]);
|
||||
current_token = t;
|
||||
break;
|
||||
}
|
||||
if (opt_random) {
|
||||
rc = securid_random_token(t);
|
||||
if (rc != ERR_NONE)
|
||||
die("error: can't generate random token\n");
|
||||
current_token = t;
|
||||
break;
|
||||
}
|
||||
if (cfg->rc_token) {
|
||||
if (is_import)
|
||||
die("error: please specify --file, --token, or --random\n");
|
||||
if (decode_rc_token(cfg, t) == ERR_NONE) {
|
||||
current_token = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(t);
|
||||
} while (0);
|
||||
|
||||
if (is_import && cfg->rc_token && !opt_force)
|
||||
die("error: token already exists; use --force to overwrite it\n");
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
int write_token_and_pin(char *token_str, char *pin_str, char *password)
|
||||
{
|
||||
free(cfg->rc_ver);
|
||||
free(cfg->rc_token);
|
||||
free(cfg->rc_pin);
|
||||
|
||||
cfg->rc_token = xstrdup(token_str);
|
||||
|
||||
if (pin_str && !password)
|
||||
cfg->rc_pin = xstrdup(pin_str);
|
||||
else if (pin_str && password) {
|
||||
cfg->rc_pin = securid_encrypt_pin(pin_str, password);
|
||||
if (!cfg->rc_pin)
|
||||
return ERR_GENERAL;
|
||||
} else
|
||||
cfg->rc_pin = NULL;
|
||||
|
||||
cfg->rc_ver = xstrdup("1");
|
||||
|
||||
return __stoken_write_rcfile(opt_rcfile, cfg, &warn);
|
||||
}
|
||||
|
||||
char *format_token(const char *token_str)
|
||||
{
|
||||
int i;
|
||||
char *out, *p;
|
||||
|
||||
if (opt_iphone)
|
||||
return xconcat("com.rsa.securid.iphone://ctf?ctfData=",
|
||||
token_str);
|
||||
else if (opt_android || opt_v3)
|
||||
return xconcat("http://127.0.0.1/securid/ctf?ctfData=",
|
||||
token_str);
|
||||
else if (!opt_blocks)
|
||||
return xstrdup(token_str);
|
||||
|
||||
/* user requested blocks of 5 digits (--blocks) */
|
||||
i = strlen(token_str);
|
||||
out = xzalloc(i + (i / 5) + 2);
|
||||
|
||||
for (i = 0, p = out; token_str[i]; i++) {
|
||||
if (i % 5 == 0 && i)
|
||||
*(p++) = '-';
|
||||
*(p++) = token_str[i];
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* common.h - Common definitions for stoken and stoken-gui
|
||||
*
|
||||
* Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __STOKEN_COMMON_H__
|
||||
#define __STOKEN_COMMON_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "stoken-internal.h"
|
||||
|
||||
static const char stoken_errstr[][32] = {
|
||||
"Success",
|
||||
"General failure",
|
||||
"Invalid length",
|
||||
"Unsupported token version",
|
||||
"Checksum failed",
|
||||
"Invalid password format",
|
||||
"Missing required password",
|
||||
"Seed decryption failed",
|
||||
"Device ID mismatch",
|
||||
"Out of memory",
|
||||
"Cannot read file",
|
||||
"Multiple tokens found in input",
|
||||
};
|
||||
|
||||
#define NOT_GUI 0
|
||||
#define IS_GUI 1
|
||||
|
||||
void prompt(const char *fmt, ...);
|
||||
void warn(const char *fmt, ...);
|
||||
void dbg(const char *fmt, ...);
|
||||
void die(const char *fmt, ...);
|
||||
|
||||
char *xstrdup(const char *s);
|
||||
char *xconcat(const char *s1, const char *s2);
|
||||
void xstrncpy(char *dest, const char *src, size_t n);
|
||||
void *xmalloc(size_t size);
|
||||
void *xzalloc(size_t size);
|
||||
|
||||
char *parse_cmdline(int argc, char **argv, int is_gui);
|
||||
int common_init(char *cmd);
|
||||
int write_token_and_pin(char *token_str, char *pin_str, char *password);
|
||||
char *format_token(const char *raw_token_str);
|
||||
|
||||
/* binary flags, long options */
|
||||
extern int opt_random, opt_keep_password, opt_blocks, opt_iphone, opt_android,
|
||||
opt_v3, opt_show_qr, opt_seed, opt_sdtid, opt_small, opt_next;
|
||||
|
||||
/* binary flags, short/long options */
|
||||
extern int opt_debug, opt_version, opt_help, opt_batch, opt_force, opt_stdin;
|
||||
|
||||
/* string arguments */
|
||||
extern char *opt_rcfile, *opt_file, *opt_token, *opt_devid, *opt_password,
|
||||
*opt_pin, *opt_use_time, *opt_new_password, *opt_new_devid,
|
||||
*opt_new_pin, *opt_template, *opt_qr;
|
||||
|
||||
/* token read from .stokenrc, if available */
|
||||
struct securid_token;
|
||||
extern struct securid_token *current_token;
|
||||
|
||||
#endif /* !__STOKEN_COMMON_H__ */
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* compat.c - compatibility functions for non-Linux hosts
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "stoken-internal.h"
|
||||
|
||||
#ifndef HAVE_STRCASESTR
|
||||
|
||||
/*
|
||||
* Source: OpenConnect
|
||||
* Copyright © 2008-2014 Intel Corporation.
|
||||
* Authors: David Woodhouse <dwmw2@infradead.org>
|
||||
*/
|
||||
char *stoken__strcasestr(const char *haystack, const char *needle)
|
||||
{
|
||||
int hlen = strlen(haystack);
|
||||
int nlen = strlen(needle);
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < hlen - nlen + 1; i++) {
|
||||
for (j = 0; j < nlen; j++) {
|
||||
if (tolower(haystack[i + j]) !=
|
||||
tolower(needle[j]))
|
||||
break;
|
||||
}
|
||||
if (j == nlen)
|
||||
return (char *)haystack + i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif /* HAVE_STRCASESTR */
|
||||
|
||||
#ifndef HAVE_MKSTEMPS
|
||||
|
||||
/*
|
||||
* Source: FreeBSD libc
|
||||
* Copyright (c) 1987, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*/
|
||||
|
||||
static const unsigned char padchar[] =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
static int
|
||||
_gettemp(char *path, int *doopen, int domkdir, int slen)
|
||||
{
|
||||
char *start, *trv, *suffp, *carryp;
|
||||
char *pad;
|
||||
struct stat sbuf;
|
||||
int rval;
|
||||
char carrybuf[MAXPATHLEN];
|
||||
|
||||
if ((doopen != NULL && domkdir) || slen < 0) {
|
||||
errno = EINVAL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (trv = path; *trv != '\0'; ++trv)
|
||||
;
|
||||
if (trv - path >= MAXPATHLEN) {
|
||||
errno = ENAMETOOLONG;
|
||||
return (0);
|
||||
}
|
||||
trv -= slen;
|
||||
suffp = trv;
|
||||
--trv;
|
||||
if (trv < path || NULL != strchr(suffp, '/')) {
|
||||
errno = EINVAL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Fill space with random characters */
|
||||
while (trv >= path && *trv == 'X') {
|
||||
uint32_t r = rand() % (sizeof(padchar) - 1);
|
||||
*trv-- = padchar[r];
|
||||
}
|
||||
start = trv + 1;
|
||||
|
||||
/* save first combination of random characters */
|
||||
memcpy(carrybuf, start, suffp - start);
|
||||
|
||||
/*
|
||||
* check the target directory.
|
||||
*/
|
||||
if (doopen != NULL || domkdir) {
|
||||
for (; trv > path; --trv) {
|
||||
if (*trv == '/') {
|
||||
*trv = '\0';
|
||||
rval = stat(path, &sbuf);
|
||||
*trv = '/';
|
||||
if (rval != 0)
|
||||
return (0);
|
||||
if (!S_ISDIR(sbuf.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (doopen) {
|
||||
if ((*doopen =
|
||||
open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
|
||||
return (1);
|
||||
if (errno != EEXIST)
|
||||
return (0);
|
||||
} /* else if (domkdir) {
|
||||
if (mkdir(path, 0700) == 0)
|
||||
return (1);
|
||||
if (errno != EEXIST)
|
||||
return (0);
|
||||
} else if (lstat(path, &sbuf))
|
||||
return (errno == ENOENT); */
|
||||
|
||||
/* If we have a collision, cycle through the space of filenames */
|
||||
for (trv = start, carryp = carrybuf;;) {
|
||||
/* have we tried all possible permutations? */
|
||||
if (trv == suffp)
|
||||
return (0); /* yes - exit with EEXIST */
|
||||
pad = strchr(padchar, *trv);
|
||||
if (pad == NULL) {
|
||||
/* this should never happen */
|
||||
errno = EIO;
|
||||
return (0);
|
||||
}
|
||||
/* increment character */
|
||||
*trv = (*++pad == '\0') ? padchar[0] : *pad;
|
||||
/* carry to next position? */
|
||||
if (*trv == *carryp) {
|
||||
/* increment position and loop */
|
||||
++trv;
|
||||
++carryp;
|
||||
} else {
|
||||
/* try with new name */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
int stoken__mkstemps(char *path, int slen)
|
||||
{
|
||||
int fd;
|
||||
|
||||
return (_gettemp(path, &fd, 0, slen) ? fd : -1);
|
||||
}
|
||||
|
||||
#endif /* HAVE_MKSTEMPS */
|
||||
|
||||
#if !defined(HAVE_GMTIME_R) && defined(_WIN32)
|
||||
struct tm *stoken__gmtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
/*
|
||||
* This trick only works on Windows, because Windows gmtime()
|
||||
* provides a dedicated buffer per-thread:
|
||||
*
|
||||
* http://msdn.microsoft.com/en-us/library/0z9czt0w.aspx
|
||||
*/
|
||||
memcpy(result, gmtime(timep), sizeof(struct tm));
|
||||
return result;
|
||||
}
|
||||
#endif /* !defined(HAVE_GMTIME_R) && defined(_WIN32) */
|
||||
|
||||
#ifndef HAVE_TIMEGM
|
||||
|
||||
/*
|
||||
* Source: Android Bionic libc
|
||||
* Copyright (c) 2007-2008 Michael G Schwern
|
||||
* Originally derived from Paul Sheer's pivotal_gmtime_r.c
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
static const int julian_days_by_month[2][12] = {
|
||||
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
|
||||
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
|
||||
};
|
||||
|
||||
static const int length_of_year[2] = { 365, 366 };
|
||||
static const int days_in_gregorian_cycle = ((365 * 400) + 100 - 4 + 1);
|
||||
|
||||
#define IS_LEAP(n) ((!(((n) + 1900) % 400) || \
|
||||
(!(((n) + 1900) % 4) && \
|
||||
(((n) + 1900) % 100))) != 0)
|
||||
|
||||
time_t stoken__timegm(struct tm *date)
|
||||
{
|
||||
time_t days = 0;
|
||||
time_t seconds = 0;
|
||||
int64_t year;
|
||||
int64_t orig_year = (int64_t) date->tm_year;
|
||||
int cycles = 0;
|
||||
|
||||
if (orig_year > 100) {
|
||||
cycles = (orig_year - 100) / 400;
|
||||
orig_year -= cycles * 400;
|
||||
days += (time_t) cycles *days_in_gregorian_cycle;
|
||||
} else if (orig_year < -300) {
|
||||
cycles = (orig_year - 100) / 400;
|
||||
orig_year -= cycles * 400;
|
||||
days += (time_t) cycles *days_in_gregorian_cycle;
|
||||
}
|
||||
|
||||
if (orig_year > 70) {
|
||||
year = 70;
|
||||
while (year < orig_year) {
|
||||
days += length_of_year[IS_LEAP(year)];
|
||||
year++;
|
||||
}
|
||||
} else if (orig_year < 70) {
|
||||
year = 69;
|
||||
do {
|
||||
days -= length_of_year[IS_LEAP(year)];
|
||||
year--;
|
||||
} while (year >= orig_year);
|
||||
}
|
||||
|
||||
days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon];
|
||||
days += date->tm_mday - 1;
|
||||
|
||||
seconds = days * 60 * 60 * 24;
|
||||
|
||||
seconds += date->tm_hour * 60 * 60;
|
||||
seconds += date->tm_min * 60;
|
||||
seconds += date->tm_sec;
|
||||
|
||||
return (seconds);
|
||||
}
|
||||
|
||||
#endif /* HAVE_TIMEGM */
|
|
@ -0,0 +1,466 @@
|
|||
/*
|
||||
* gui.c - stoken gtk+ interface
|
||||
*
|
||||
* Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "securid.h"
|
||||
|
||||
#define WINDOW_TITLE "Software Token"
|
||||
|
||||
#define EXP_WARN_DAYS 14
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef UIDIR
|
||||
#define UIDIR "."
|
||||
#define PIXMAP_DIR "."
|
||||
#else
|
||||
#define PIXMAP_DIR DATA_DIR "/pixmaps"
|
||||
#endif
|
||||
|
||||
static GtkWidget *tokencode_text, *next_tokencode_text, *progress_bar;
|
||||
|
||||
static char tokencode_str[16];
|
||||
static char next_tokencode_str[16];
|
||||
|
||||
static int last_sec = -1;
|
||||
static int token_sec;
|
||||
static long time_adjustment;
|
||||
|
||||
static int token_days_left;
|
||||
static int token_interval;
|
||||
static int token_uses_pin;
|
||||
static int skipped_pin;
|
||||
|
||||
static gboolean delete_callback(GtkWidget *widget, GdkEvent *event,
|
||||
gpointer data)
|
||||
{
|
||||
gtk_main_quit();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void copy_tokencode(gpointer user_data)
|
||||
{
|
||||
GdkDisplay *disp = gdk_display_get_default();
|
||||
GtkClipboard *clip;
|
||||
char *str = user_data;
|
||||
|
||||
/* CLIPBOARD - Control-V in most applications */
|
||||
clip = gtk_clipboard_get_for_display(disp, GDK_SELECTION_CLIPBOARD);
|
||||
gtk_clipboard_set_text(clip, str, -1);
|
||||
|
||||
/* PRIMARY - middle-click in xterm */
|
||||
clip = gtk_clipboard_get_for_display(disp, GDK_SELECTION_PRIMARY);
|
||||
gtk_clipboard_set_text(clip, str, -1);
|
||||
}
|
||||
|
||||
static void clicked_to_clipboard(GtkButton *button, gpointer user_data)
|
||||
{
|
||||
copy_tokencode(user_data);
|
||||
}
|
||||
|
||||
static gboolean press_to_clipboard(GtkWidget *widget, GdkEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
copy_tokencode(user_data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean draw_progress_bar_callback(GtkWidget *widget, cairo_t *cr,
|
||||
gpointer data)
|
||||
{
|
||||
guint width, height, boundary;
|
||||
|
||||
width = gtk_widget_get_allocated_width(widget);
|
||||
height = gtk_widget_get_allocated_height(widget);
|
||||
|
||||
boundary = width * token_sec / (token_interval - 1);
|
||||
|
||||
cairo_set_source_rgb(cr, 0.3, 0.4, 0.5);
|
||||
cairo_rectangle(cr, 0, 0, boundary, height);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
||||
cairo_rectangle(cr, boundary, 0, width - boundary, height);
|
||||
cairo_fill(cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static time_t adjusted_time(void)
|
||||
{
|
||||
return time(NULL) + time_adjustment;
|
||||
}
|
||||
|
||||
static void parse_opt_use_time(void)
|
||||
{
|
||||
long new_time;
|
||||
|
||||
if (!opt_use_time)
|
||||
return;
|
||||
else if (sscanf(opt_use_time, "+%ld", &new_time) == 1)
|
||||
time_adjustment = new_time;
|
||||
else if (sscanf(opt_use_time, "-%ld", &new_time) == 1)
|
||||
time_adjustment = -new_time;
|
||||
else
|
||||
die("error: 'stoken-gui --use-time' must specify a +/- offset\n");
|
||||
}
|
||||
|
||||
static gint update_tokencode(gpointer data)
|
||||
{
|
||||
time_t now = adjusted_time();
|
||||
struct tm *tm;
|
||||
char str[128], *formatted;
|
||||
|
||||
tm = gmtime(&now);
|
||||
if ((tm->tm_sec >= 30 && last_sec < 30) ||
|
||||
(tm->tm_sec < 30 && last_sec >= 30) ||
|
||||
last_sec == -1) {
|
||||
last_sec = tm->tm_sec;
|
||||
securid_compute_tokencode(current_token, now, tokencode_str);
|
||||
securid_compute_tokencode(current_token, now + token_interval,
|
||||
next_tokencode_str);
|
||||
}
|
||||
|
||||
token_sec = token_interval - (tm->tm_sec % token_interval) - 1;
|
||||
gtk_widget_queue_draw(GTK_WIDGET(progress_bar));
|
||||
|
||||
formatted = stoken_format_tokencode(tokencode_str);
|
||||
if (!formatted)
|
||||
die("out of memory\n");
|
||||
|
||||
snprintf(str, sizeof(str),
|
||||
"<span size=\"xx-large\" weight=\"bold\">%s</span>",
|
||||
formatted);
|
||||
gtk_label_set_markup(GTK_LABEL(tokencode_text), str);
|
||||
free(formatted);
|
||||
|
||||
if (next_tokencode_text) {
|
||||
formatted = stoken_format_tokencode(next_tokencode_str);
|
||||
if (!formatted)
|
||||
die("out of memory\n");
|
||||
gtk_label_set_text(GTK_LABEL(next_tokencode_text), formatted);
|
||||
free(formatted);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void __error_dialog(GtkWindow *parent, const char *heading,
|
||||
const char *msg, int is_warning)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_message_dialog_new(parent,
|
||||
parent ? GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT : 0,
|
||||
is_warning ? GTK_MESSAGE_WARNING : GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_OK, "%s", heading);
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
"%s", msg);
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), WINDOW_TITLE);
|
||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
if (!is_warning)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void error_dialog(const char *heading, const char *msg)
|
||||
{
|
||||
return __error_dialog(NULL, heading, msg, 0);
|
||||
}
|
||||
|
||||
static void warning_dialog(GtkWidget *parent, const char *heading,
|
||||
const char *msg)
|
||||
{
|
||||
return __error_dialog(GTK_WINDOW(parent), heading, msg, 1);
|
||||
}
|
||||
|
||||
static GtkWidget *create_app_window_common(GtkBuilder *builder)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
|
||||
progress_bar = GTK_WIDGET(
|
||||
gtk_builder_get_object(builder, "progress_bar"));
|
||||
g_signal_connect(progress_bar, "draw",
|
||||
G_CALLBACK(draw_progress_bar_callback), NULL);
|
||||
|
||||
tokencode_text = GTK_WIDGET(
|
||||
gtk_builder_get_object(builder, "tokencode_text"));
|
||||
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(builder, "app_window"));
|
||||
g_signal_connect(widget, "delete-event", G_CALLBACK(delete_callback),
|
||||
NULL);
|
||||
return widget;
|
||||
}
|
||||
|
||||
static void set_red_label(GtkWidget *widget, const char *text)
|
||||
{
|
||||
char tmp[BUFLEN];
|
||||
|
||||
snprintf(tmp, BUFLEN,
|
||||
"<span weight=\"bold\" foreground=\"red\">%s</span>", text);
|
||||
gtk_label_set_markup(GTK_LABEL(widget), tmp);
|
||||
}
|
||||
|
||||
static void format_exp_date(GtkWidget *widget)
|
||||
{
|
||||
time_t exp = securid_unix_exp_date(current_token);
|
||||
char tmp[BUFLEN];
|
||||
|
||||
/* FIXME: localization */
|
||||
strftime(tmp, BUFLEN, "%Y-%m-%d", gmtime(&exp));
|
||||
|
||||
if (token_days_left < EXP_WARN_DAYS)
|
||||
set_red_label(widget, tmp);
|
||||
else
|
||||
gtk_label_set_text(GTK_LABEL(widget), tmp);
|
||||
}
|
||||
|
||||
/* gtk_builder_new_from_file() requires libgtk >= 3.10 */
|
||||
static GtkBuilder *__gtk_builder_new_from_file(const gchar *filename)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
|
||||
builder = gtk_builder_new();
|
||||
if (gtk_builder_add_from_file(builder, filename, NULL) == 0)
|
||||
die("can't import '%s'\n", filename);
|
||||
return builder;
|
||||
}
|
||||
|
||||
static GtkWidget *create_app_window(void)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *widget;
|
||||
|
||||
builder = __gtk_builder_new_from_file(UIDIR "/tokencode-detail.ui");
|
||||
|
||||
/* static token info */
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(builder, "token_sn_text"));
|
||||
gtk_label_set_text(GTK_LABEL(widget), current_token->serial);
|
||||
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(builder, "exp_date_text"));
|
||||
format_exp_date(widget);
|
||||
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(builder, "using_pin_text"));
|
||||
if (!token_uses_pin)
|
||||
gtk_label_set_text(GTK_LABEL(widget), "Not required");
|
||||
else if (skipped_pin)
|
||||
set_red_label(widget, "No");
|
||||
else
|
||||
gtk_label_set_text(GTK_LABEL(widget), "Yes");
|
||||
|
||||
/* buttons */
|
||||
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(builder, "copy_button"));
|
||||
g_signal_connect(widget, "clicked", G_CALLBACK(clicked_to_clipboard),
|
||||
&tokencode_str);
|
||||
|
||||
/* next tokencode */
|
||||
|
||||
next_tokencode_text = GTK_WIDGET(
|
||||
gtk_builder_get_object(builder, "next_tokencode_text"));
|
||||
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(builder,
|
||||
"next_tokencode_eventbox"));
|
||||
g_signal_connect(widget, "button-press-event",
|
||||
G_CALLBACK(press_to_clipboard), &next_tokencode_str);
|
||||
|
||||
return create_app_window_common(builder);
|
||||
}
|
||||
|
||||
static GtkWidget *create_small_app_window(void)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *widget;
|
||||
|
||||
builder = __gtk_builder_new_from_file(UIDIR "/tokencode-small.ui");
|
||||
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(builder, "event_box"));
|
||||
g_signal_connect(widget, "button-press-event",
|
||||
G_CALLBACK(press_to_clipboard), &tokencode_str);
|
||||
|
||||
return create_app_window_common(builder);
|
||||
}
|
||||
|
||||
static char *do_password_dialog(const char *ui_file)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *widget, *dialog;
|
||||
gint resp;
|
||||
char *ret = NULL;
|
||||
|
||||
builder = __gtk_builder_new_from_file(ui_file);
|
||||
dialog = GTK_WIDGET(gtk_builder_get_object(builder, "dialog_window"));
|
||||
gtk_widget_show_all(dialog);
|
||||
resp = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
|
||||
if (resp == GTK_RESPONSE_OK) {
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(builder, "password"));
|
||||
ret = strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int request_credentials(struct securid_token *t)
|
||||
{
|
||||
int rc, pass_required = 0, pin_required = 0;
|
||||
|
||||
if (securid_pass_required(t)) {
|
||||
pass_required = 1;
|
||||
if (opt_password) {
|
||||
rc = securid_decrypt_seed(t, opt_password, NULL);
|
||||
if (rc == ERR_DECRYPT_FAILED)
|
||||
warn("warning: --password parameter is incorrect\n");
|
||||
else if (rc != ERR_NONE)
|
||||
error_dialog("Token decrypt error",
|
||||
stoken_errstr[rc]);
|
||||
else
|
||||
pass_required = 0;
|
||||
}
|
||||
} else {
|
||||
rc = securid_decrypt_seed(t, opt_password, NULL);
|
||||
if (rc != ERR_NONE)
|
||||
error_dialog("Token decrypt error", stoken_errstr[rc]);
|
||||
}
|
||||
|
||||
while (pass_required) {
|
||||
const char *pass =
|
||||
do_password_dialog(UIDIR "/password-dialog.ui");
|
||||
if (!pass)
|
||||
return ERR_MISSING_PASSWORD;
|
||||
rc = securid_decrypt_seed(t, pass, NULL);
|
||||
if (rc == ERR_NONE) {
|
||||
if (t->enc_pin_str) {
|
||||
rc = securid_decrypt_pin(t->enc_pin_str,
|
||||
pass, t->pin);
|
||||
if (rc != ERR_NONE)
|
||||
error_dialog("PIN decrypt error",
|
||||
stoken_errstr[rc]);
|
||||
}
|
||||
|
||||
pass_required = 0;
|
||||
} else if (rc == ERR_DECRYPT_FAILED)
|
||||
warning_dialog(NULL, "Bad password",
|
||||
"Please enter the correct password for this seed.");
|
||||
else
|
||||
error_dialog("Token decrypt error", stoken_errstr[rc]);
|
||||
}
|
||||
|
||||
if (securid_pin_required(t)) {
|
||||
pin_required = 1;
|
||||
if (opt_pin) {
|
||||
if (securid_pin_format_ok(opt_pin) == ERR_NONE) {
|
||||
xstrncpy(t->pin, opt_pin, MAX_PIN + 1);
|
||||
pin_required = 0;
|
||||
} else
|
||||
warn("warning: --pin argument is invalid\n");
|
||||
} else if (strlen(t->pin) || t->enc_pin_str)
|
||||
pin_required = 0;
|
||||
}
|
||||
|
||||
while (pin_required) {
|
||||
const char *pin =
|
||||
do_password_dialog(UIDIR "/pin-dialog.ui");
|
||||
if (!pin) {
|
||||
skipped_pin = 1;
|
||||
xstrncpy(t->pin, "0000", MAX_PIN + 1);
|
||||
break;
|
||||
}
|
||||
if (securid_pin_format_ok(pin) != ERR_NONE) {
|
||||
warning_dialog(NULL, "Bad PIN",
|
||||
"Please enter 4-8 digits, or click Skip for no PIN.");
|
||||
} else {
|
||||
xstrncpy(t->pin, pin, MAX_PIN + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window;
|
||||
char *cmd;
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
gtk_window_set_default_icon_from_file(
|
||||
PIXMAP_DIR "/stoken-gui.png", NULL);
|
||||
|
||||
cmd = parse_cmdline(argc, argv, IS_GUI);
|
||||
|
||||
/* check for a couple of error conditions */
|
||||
|
||||
if (common_init(cmd))
|
||||
error_dialog("Application error",
|
||||
"Unable to initialize crypto library.");
|
||||
|
||||
if (!current_token)
|
||||
error_dialog("Missing token",
|
||||
"Please use 'stoken import' to add a new seed.");
|
||||
|
||||
if (securid_devid_required(current_token))
|
||||
error_dialog("Unsupported token",
|
||||
"Please use 'stoken' to handle tokens encrypted with a device ID.");
|
||||
|
||||
/* check for token expiration */
|
||||
parse_opt_use_time();
|
||||
token_days_left = securid_check_exp(current_token, adjusted_time());
|
||||
|
||||
if (!opt_force && !opt_small) {
|
||||
if (token_days_left < 0)
|
||||
error_dialog("Token expired",
|
||||
"Please obtain a new token from your administrator.");
|
||||
|
||||
if (token_days_left < EXP_WARN_DAYS) {
|
||||
char msg[BUFLEN];
|
||||
|
||||
sprintf(msg, "This token will expire in %d day%s.",
|
||||
token_days_left,
|
||||
token_days_left == 1 ? "" : "s");
|
||||
warning_dialog(NULL, "Expiration warning", msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* request password / PIN, if missing */
|
||||
if (request_credentials(current_token) != ERR_NONE)
|
||||
return 1;
|
||||
|
||||
token_interval = securid_token_interval(current_token);
|
||||
token_uses_pin = securid_pin_required(current_token);
|
||||
|
||||
window = opt_small ? create_small_app_window() : create_app_window();
|
||||
|
||||
update_tokencode(NULL);
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
g_timeout_add(250, update_tokencode, NULL);
|
||||
gtk_main();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
* jni.c - stoken Java Native Interface
|
||||
*
|
||||
* Copyright 2014 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <jni.h>
|
||||
#include "stoken.h"
|
||||
|
||||
/* these need to match LibStoken.java */
|
||||
#define SUCCESS ( 0)
|
||||
#define INVALID_FORMAT (-1)
|
||||
#define IO_ERROR (-2)
|
||||
#define FILE_NOT_FOUND (-3)
|
||||
|
||||
struct libctx {
|
||||
JNIEnv *jenv;
|
||||
jobject jobj;
|
||||
struct stoken_ctx *instance;
|
||||
};
|
||||
|
||||
static void throw_excep(JNIEnv *jenv, const char *exc, int line)
|
||||
{
|
||||
jclass excep;
|
||||
char msg[64];
|
||||
|
||||
snprintf(msg, 64, "%s:%d", __FILE__, line);
|
||||
|
||||
(*jenv)->ExceptionClear(jenv);
|
||||
excep = (*jenv)->FindClass(jenv, exc);
|
||||
if (excep)
|
||||
(*jenv)->ThrowNew(jenv, excep, msg);
|
||||
}
|
||||
|
||||
#define OOM(jenv) do { throw_excep(jenv, "java/lang/OutOfMemoryError", __LINE__); } while (0)
|
||||
|
||||
static int translate_errno(JNIEnv *jenv, int err)
|
||||
{
|
||||
switch (err) {
|
||||
case 0:
|
||||
return SUCCESS;
|
||||
case -EINVAL:
|
||||
return INVALID_FORMAT;
|
||||
case -ENOENT:
|
||||
return FILE_NOT_FOUND;
|
||||
case -ENOMEM:
|
||||
throw_excep(jenv, "java/lang/OutOfMemoryError", __LINE__);
|
||||
/* falls through */
|
||||
case -EIO:
|
||||
default:
|
||||
return IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static struct libctx *getctx(JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
jclass jcls = (*jenv)->GetObjectClass(jenv, jobj);
|
||||
jfieldID jfld = (*jenv)->GetFieldID(jenv, jcls, "libctx", "J");
|
||||
if (!jfld)
|
||||
return NULL;
|
||||
return (void *)(unsigned long)(*jenv)->GetLongField(jenv, jobj, jfld);
|
||||
}
|
||||
|
||||
static int set_int(struct libctx *ctx, jobject jobj, const char *name, int value)
|
||||
{
|
||||
jclass jcls = (*ctx->jenv)->GetObjectClass(ctx->jenv, jobj);
|
||||
jfieldID jfld = (*ctx->jenv)->GetFieldID(ctx->jenv, jcls, name, "I");
|
||||
|
||||
if (!jfld)
|
||||
return -1;
|
||||
(*ctx->jenv)->SetIntField(ctx->jenv, jobj, jfld, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_long(struct libctx *ctx, jobject jobj, const char *name, uint64_t value)
|
||||
{
|
||||
jclass jcls = (*ctx->jenv)->GetObjectClass(ctx->jenv, jobj);
|
||||
jfieldID jfld = (*ctx->jenv)->GetFieldID(ctx->jenv, jcls, name, "J");
|
||||
|
||||
if (!jfld)
|
||||
return -1;
|
||||
(*ctx->jenv)->SetLongField(ctx->jenv, jobj, jfld, (jlong)value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_bool(struct libctx *ctx, jobject jobj, const char *name, int value)
|
||||
{
|
||||
jclass jcls = (*ctx->jenv)->GetObjectClass(ctx->jenv, jobj);
|
||||
jfieldID jfld = (*ctx->jenv)->GetFieldID(ctx->jenv, jcls, name, "Z");
|
||||
|
||||
if (!jfld)
|
||||
return -1;
|
||||
(*ctx->jenv)->SetBooleanField(ctx->jenv, jobj, jfld, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static jstring dup_to_jstring(JNIEnv *jenv, const char *in)
|
||||
{
|
||||
/*
|
||||
* Many implementations of NewStringUTF() will return NULL on
|
||||
* NULL input, but that isn't guaranteed:
|
||||
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35979
|
||||
*/
|
||||
return in ? (*jenv)->NewStringUTF(jenv, in) : NULL;
|
||||
}
|
||||
|
||||
static int set_string(struct libctx *ctx, jobject jobj, const char *name, const char *value)
|
||||
{
|
||||
jclass jcls = (*ctx->jenv)->GetObjectClass(ctx->jenv, jobj);
|
||||
jfieldID jfld = (*ctx->jenv)->GetFieldID(ctx->jenv, jcls, name, "Ljava/lang/String;");
|
||||
jstring jarg;
|
||||
|
||||
if (!jfld)
|
||||
return -1;
|
||||
|
||||
jarg = dup_to_jstring(ctx->jenv, value);
|
||||
if (value && !jarg)
|
||||
return -1;
|
||||
(*ctx->jenv)->SetObjectField(ctx->jenv, jobj, jfld, jarg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_org_stoken_LibStoken_init(
|
||||
JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
struct libctx *ctx = calloc(1, sizeof(*ctx));
|
||||
|
||||
if (!ctx)
|
||||
goto bad;
|
||||
|
||||
ctx->jenv = jenv;
|
||||
ctx->jobj = (*jenv)->NewGlobalRef(jenv, jobj);
|
||||
if (!ctx->jobj)
|
||||
goto bad_free_ctx;
|
||||
|
||||
ctx->instance = stoken_new();
|
||||
if (!ctx->instance)
|
||||
goto bad_delete_ref;
|
||||
|
||||
return (jlong)(unsigned long)ctx;
|
||||
|
||||
bad_delete_ref:
|
||||
(*jenv)->DeleteGlobalRef(jenv, ctx->jobj);
|
||||
bad_free_ctx:
|
||||
free(ctx);
|
||||
bad:
|
||||
OOM(jenv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_stoken_LibStoken_free(
|
||||
JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
stoken_destroy(ctx->instance);
|
||||
(*jenv)->DeleteGlobalRef(jenv, ctx->jobj);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_stoken_LibStoken_importRCFile(
|
||||
JNIEnv *jenv, jobject jobj, jstring jarg0)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
const char *arg0;
|
||||
int ret;
|
||||
|
||||
if (!jarg0)
|
||||
return translate_errno(jenv, -EINVAL);
|
||||
|
||||
arg0 = (*jenv)->GetStringUTFChars(jenv, jarg0, NULL);
|
||||
if (!arg0)
|
||||
ret = -ENOMEM;
|
||||
else
|
||||
ret = stoken_import_rcfile(ctx->instance, arg0);
|
||||
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jarg0, arg0);
|
||||
return translate_errno(jenv, ret);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_stoken_LibStoken_importString(
|
||||
JNIEnv *jenv, jobject jobj, jstring jarg0)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
const char *arg0;
|
||||
int ret;
|
||||
|
||||
if (!jarg0)
|
||||
return translate_errno(jenv, -EINVAL);
|
||||
|
||||
arg0 = (*jenv)->GetStringUTFChars(jenv, jarg0, NULL);
|
||||
if (!arg0)
|
||||
ret = -ENOMEM;
|
||||
else
|
||||
ret = stoken_import_string(ctx->instance, arg0);
|
||||
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jarg0, arg0);
|
||||
return translate_errno(jenv, ret);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_org_stoken_LibStoken_getInfo(
|
||||
JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
struct stoken_info *info;
|
||||
jmethodID mid;
|
||||
jclass jcls;
|
||||
|
||||
jcls = (*ctx->jenv)->FindClass(ctx->jenv,
|
||||
"org/stoken/LibStoken$StokenInfo");
|
||||
if (jcls == NULL)
|
||||
return NULL;
|
||||
|
||||
mid = (*ctx->jenv)->GetMethodID(ctx->jenv, jcls, "<init>", "()V");
|
||||
if (!mid)
|
||||
return NULL;
|
||||
jobj = (*ctx->jenv)->NewObject(ctx->jenv, jcls, mid);
|
||||
if (!jobj)
|
||||
return NULL;
|
||||
|
||||
info = stoken_get_info(ctx->instance);
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
if (set_string(ctx, jobj, "serial", info->serial) ||
|
||||
set_long(ctx, jobj, "unixExpDate", info->exp_date) ||
|
||||
set_int(ctx, jobj, "interval", info->interval) ||
|
||||
set_int(ctx, jobj, "tokenVersion", info->token_version) ||
|
||||
set_bool(ctx, jobj, "usesPin", info->uses_pin))
|
||||
jobj = NULL;
|
||||
|
||||
free(info);
|
||||
return jobj;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_stoken_LibStoken_getMinPIN(
|
||||
JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
int min_pin, max_pin;
|
||||
|
||||
stoken_pin_range(ctx->instance, &min_pin, &max_pin);
|
||||
return min_pin;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_stoken_LibStoken_getMaxPIN(
|
||||
JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
int min_pin, max_pin;
|
||||
|
||||
stoken_pin_range(ctx->instance, &min_pin, &max_pin);
|
||||
return max_pin;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_stoken_LibStoken_isPINRequired(
|
||||
JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
return !!stoken_pin_required(ctx->instance);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_stoken_LibStoken_isPassRequired(
|
||||
JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
return !!stoken_pass_required(ctx->instance);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_stoken_LibStoken_isDevIDRequired(
|
||||
JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
return !!stoken_devid_required(ctx->instance);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_stoken_LibStoken_checkPIN(
|
||||
JNIEnv *jenv, jobject jobj, jstring jarg0)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
const char *arg0;
|
||||
int ret;
|
||||
|
||||
if (!jarg0)
|
||||
return translate_errno(jenv, -EINVAL);
|
||||
|
||||
arg0 = (*jenv)->GetStringUTFChars(jenv, jarg0, NULL);
|
||||
if (!arg0)
|
||||
ret = -ENOMEM;
|
||||
else
|
||||
ret = stoken_check_pin(ctx->instance, arg0);
|
||||
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jarg0, arg0);
|
||||
return !translate_errno(jenv, ret);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_stoken_LibStoken_checkDevID(
|
||||
JNIEnv *jenv, jobject jobj, jstring jarg0)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
const char *arg0;
|
||||
int ret;
|
||||
|
||||
if (!jarg0)
|
||||
return translate_errno(jenv, -EINVAL);
|
||||
|
||||
arg0 = (*jenv)->GetStringUTFChars(jenv, jarg0, NULL);
|
||||
if (!arg0)
|
||||
ret = -ENOMEM;
|
||||
else
|
||||
ret = stoken_check_devid(ctx->instance, arg0);
|
||||
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jarg0, arg0);
|
||||
return !translate_errno(jenv, ret);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_org_stoken_LibStoken_getGUIDList(
|
||||
JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
jmethodID mid;
|
||||
jclass jcls;
|
||||
const struct stoken_guid *guidlist = stoken_get_guid_list();
|
||||
int i, len;
|
||||
jobjectArray jarr;
|
||||
|
||||
for (len = 0; guidlist[len].tag != NULL; len++)
|
||||
;
|
||||
|
||||
jcls = (*ctx->jenv)->FindClass(ctx->jenv,
|
||||
"org/stoken/LibStoken$StokenGUID");
|
||||
if (jcls == NULL)
|
||||
return NULL;
|
||||
|
||||
mid = (*ctx->jenv)->GetMethodID(ctx->jenv, jcls, "<init>", "()V");
|
||||
if (!mid)
|
||||
return NULL;
|
||||
jarr = (*ctx->jenv)->NewObjectArray(ctx->jenv, len, jcls, NULL);
|
||||
if (!jarr)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
const struct stoken_guid *g = &guidlist[i];
|
||||
|
||||
jobj = (*ctx->jenv)->NewObject(ctx->jenv, jcls, mid);
|
||||
if (!jobj)
|
||||
return NULL;
|
||||
|
||||
if (set_string(ctx, jobj, "tag", g->tag) ||
|
||||
set_string(ctx, jobj, "longName", g->long_name) ||
|
||||
set_string(ctx, jobj, "GUID", g->guid))
|
||||
return NULL;
|
||||
|
||||
(*ctx->jenv)->SetObjectArrayElement(ctx->jenv, jarr, i, jobj);
|
||||
}
|
||||
|
||||
return jarr;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_stoken_LibStoken_decryptSeed(
|
||||
JNIEnv *jenv, jobject jobj, jstring jarg0, jstring jarg1)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
const char *arg0 = NULL, *arg1 = NULL;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if (jarg0) {
|
||||
arg0 = (*jenv)->GetStringUTFChars(jenv, jarg0, NULL);
|
||||
if (!arg0)
|
||||
goto out;
|
||||
}
|
||||
if (jarg1) {
|
||||
arg1 = (*jenv)->GetStringUTFChars(jenv, jarg1, NULL);
|
||||
if (!arg1)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = stoken_decrypt_seed(ctx->instance, arg0, arg1);
|
||||
|
||||
out:
|
||||
if (arg1)
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jarg1, arg1);
|
||||
if (arg0)
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jarg0, arg0);
|
||||
return translate_errno(jenv, ret);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_stoken_LibStoken_encryptSeed(
|
||||
JNIEnv *jenv, jobject jobj, jstring jarg0, jstring jarg1)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
const char *arg0 = NULL, *arg1 = NULL;
|
||||
char *ret;
|
||||
jstring jret = NULL;
|
||||
|
||||
if (jarg0) {
|
||||
arg0 = (*jenv)->GetStringUTFChars(jenv, jarg0, NULL);
|
||||
if (!arg0)
|
||||
goto out;
|
||||
}
|
||||
if (jarg1) {
|
||||
arg1 = (*jenv)->GetStringUTFChars(jenv, jarg1, NULL);
|
||||
if (!arg1)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = stoken_encrypt_seed(ctx->instance, arg0, arg1);
|
||||
jret = ret ? (*jenv)->NewStringUTF(jenv, ret) : NULL;
|
||||
free(ret);
|
||||
|
||||
out:
|
||||
if (arg1)
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jarg1, arg1);
|
||||
if (arg0)
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jarg0, arg0);
|
||||
return jret;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_stoken_LibStoken_computeTokencode(
|
||||
JNIEnv *jenv, jobject jobj, jlong jwhen, jstring jpin)
|
||||
{
|
||||
struct libctx *ctx = getctx(jenv, jobj);
|
||||
const char *pin = NULL;
|
||||
time_t when = jwhen ? jwhen : time(NULL);
|
||||
char tokencode[STOKEN_MAX_TOKENCODE + 1];
|
||||
jstring ret = NULL;
|
||||
|
||||
if (jpin) {
|
||||
pin = (*jenv)->GetStringUTFChars(jenv, jpin, NULL);
|
||||
if (!pin) {
|
||||
OOM(jenv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (stoken_compute_tokencode(ctx->instance, when, pin, tokencode) == 0)
|
||||
ret = (*jenv)->NewStringUTF(jenv, tokencode);
|
||||
|
||||
if (jpin)
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jpin, pin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_stoken_LibStoken_formatTokencode(
|
||||
JNIEnv *jenv, jobject jobj, jstring jarg0)
|
||||
{
|
||||
const char *arg0;
|
||||
char *ret;
|
||||
jstring jret = NULL;
|
||||
|
||||
if (!jarg0)
|
||||
return NULL;
|
||||
|
||||
arg0 = (*jenv)->GetStringUTFChars(jenv, jarg0, NULL);
|
||||
if (!arg0)
|
||||
return NULL;
|
||||
|
||||
ret = stoken_format_tokencode(arg0);
|
||||
jret = (*jenv)->NewStringUTF(jenv, ret);
|
||||
|
||||
free(ret);
|
||||
(*jenv)->ReleaseStringUTFChars(jenv, jarg0, arg0);
|
||||
|
||||
return jret;
|
||||
}
|
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
* library.c - libstoken library implementation
|
||||
*
|
||||
* Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "securid.h"
|
||||
#include "sdtid.h"
|
||||
#include "stoken-internal.h"
|
||||
|
||||
struct stoken_ctx {
|
||||
struct securid_token *t;
|
||||
struct stoken_cfg cfg;
|
||||
};
|
||||
|
||||
static struct stoken_guid stoken_guid_list[] = {
|
||||
{ "iphone", "iPhone", "556f1985-33dd-442c-9155-3a0e994f21b1" },
|
||||
{ "android", "Android", "a01c4380-fc01-4df0-b113-7fb98ec74694" },
|
||||
{ "bb", "BlackBerry", "868c28f8-31bf-4911-9876-ebece5c3f2ab" },
|
||||
{ "bb10", "BlackBerry 10", "b77a1d06-d505-4200-90d3-1bb397748704" },
|
||||
{ "winphone", "Windows Phone", "c483b592-63f0-4f19-b4cb-a6bce8e57159" },
|
||||
{ "win", "Windows", "8f94b226-d362-4204-ac52-3b21fa333b6f" },
|
||||
{ "mac", "Mac OSX", "d0955a53-569b-4ecc-9cf7-6c2a59d4e775" },
|
||||
{ },
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* Internal functions (only called from within the stoken package)
|
||||
***********************************************************************/
|
||||
|
||||
static int strstarts(const char *str, const char *prefix)
|
||||
{
|
||||
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
int __stoken_parse_and_decode_token(const char *str, struct securid_token *t,
|
||||
int interactive)
|
||||
{
|
||||
char buf[BUFLEN];
|
||||
const char *p;
|
||||
int i, ret;
|
||||
|
||||
memset(t, 0, sizeof(*t));
|
||||
t->interactive = interactive;
|
||||
|
||||
do {
|
||||
/* try to handle broken quoted-printable input */
|
||||
p = strcasestr(str, "ctfData=3D");
|
||||
if (p) {
|
||||
p += 10;
|
||||
break;
|
||||
}
|
||||
|
||||
/* normal iPhone/Android soft token URLs */
|
||||
p = strcasestr(str, "ctfData=");
|
||||
if (p) {
|
||||
p += 8;
|
||||
break;
|
||||
}
|
||||
|
||||
/* sdtid (XML) token format */
|
||||
p = strcasestr(str, "<?xml ");
|
||||
if (p)
|
||||
return sdtid_decode(p, t);
|
||||
|
||||
p = str;
|
||||
if (isdigit(*p))
|
||||
break;
|
||||
|
||||
/* bogus token string */
|
||||
return ERR_GENERAL;
|
||||
} while (0);
|
||||
|
||||
if (p[0] == '1' || p[0] == '2') {
|
||||
for (i = 0; *p; p++) {
|
||||
if (i >= BUFLEN - 1)
|
||||
return ERR_BAD_LEN;
|
||||
if (isdigit(*p))
|
||||
buf[i++] = *p;
|
||||
else if (*p != '-')
|
||||
break;
|
||||
}
|
||||
} else if (p[0] == 'A') {
|
||||
for (i = 0; *p; p++) {
|
||||
if (i >= BUFLEN - 1)
|
||||
return ERR_BAD_LEN;
|
||||
buf[i++] = *p;
|
||||
}
|
||||
} else
|
||||
return ERR_GENERAL;
|
||||
|
||||
buf[i] = 0;
|
||||
ret = securid_decode_token(buf, t);
|
||||
|
||||
if (strstarts(str, "com.rsa.securid.iphone://ctf") ||
|
||||
strstarts(str, "com.rsa.securid://ctf") ||
|
||||
strstarts(str, "http://127.0.0.1/securid/ctf"))
|
||||
t->is_smartphone = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int next_token(char **in, char *tok, int maxlen)
|
||||
{
|
||||
int len;
|
||||
|
||||
for (len = 0; len < BUFLEN - 1; (*in)++) {
|
||||
if (**in == 0 || **in == '\r' || **in == '\n') {
|
||||
if (len == 0)
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
if (**in == ' ' || **in == '\t') {
|
||||
if (len != 0)
|
||||
goto done;
|
||||
continue;
|
||||
}
|
||||
*(tok++) = **in;
|
||||
len++;
|
||||
}
|
||||
|
||||
/* if the loop terminates here, truncate the line and return success */
|
||||
|
||||
done:
|
||||
*tok = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_rcline(struct stoken_cfg *cfg, int linenum, char *line,
|
||||
warn_fn_t warn_fn)
|
||||
{
|
||||
char *p = line, key[BUFLEN], val[BUFLEN], **dst;
|
||||
|
||||
if (next_token(&p, key, BUFLEN) < 0)
|
||||
return ERR_NONE; /* empty line */
|
||||
|
||||
if (key[0] == '#')
|
||||
return ERR_NONE; /* comment */
|
||||
|
||||
if (next_token(&p, val, BUFLEN) < 0) {
|
||||
warn_fn("rcfile:%d: missing argument for '%s'\n", linenum, key);
|
||||
return ERR_GENERAL;
|
||||
}
|
||||
|
||||
dst = NULL;
|
||||
if (strcasecmp(key, "version") == 0)
|
||||
dst = &cfg->rc_ver;
|
||||
else if (strcasecmp(key, "token") == 0)
|
||||
dst = &cfg->rc_token;
|
||||
else if (strcasecmp(key, "pin") == 0)
|
||||
dst = &cfg->rc_pin;
|
||||
|
||||
if (!dst) {
|
||||
/* this isn't treated as a fatal error */
|
||||
warn_fn("rcfile:%d: unrecognized option '%s'\n", linenum, key);
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
free(*dst);
|
||||
*dst = strdup(val);
|
||||
if (!*dst) {
|
||||
warn_fn("rcfile:%d: out of memory\n", linenum);
|
||||
return ERR_GENERAL;
|
||||
}
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
static int fopen_rcfile(const char *override, const char *mode,
|
||||
warn_fn_t warn_fn, FILE **f)
|
||||
{
|
||||
char *homedir;
|
||||
const char *file = override;
|
||||
char filename[BUFLEN];
|
||||
mode_t old_umask;
|
||||
|
||||
if (!override) {
|
||||
homedir = getenv("HOME");
|
||||
if (!homedir) {
|
||||
homedir = getenv("USERPROFILE");
|
||||
}
|
||||
if (!homedir) {
|
||||
warn_fn("rcfile: HOME is not set so I can't read '%s'\n",
|
||||
RC_NAME);
|
||||
return ERR_GENERAL;
|
||||
}
|
||||
|
||||
snprintf(filename, BUFLEN, "%s/%s", homedir, RC_NAME);
|
||||
file = filename;
|
||||
}
|
||||
|
||||
/* force mode 0600 on creation */
|
||||
old_umask = umask(0177);
|
||||
*f = fopen(file, mode);
|
||||
umask(old_umask);
|
||||
|
||||
if (!*f && override)
|
||||
warn_fn("rcfile: can't open '%s'\n", override);
|
||||
|
||||
return *f ? ERR_NONE : ERR_GENERAL;
|
||||
}
|
||||
|
||||
void __stoken_zap_rcfile_data(struct stoken_cfg *cfg)
|
||||
{
|
||||
free(cfg->rc_ver);
|
||||
free(cfg->rc_token);
|
||||
free(cfg->rc_pin);
|
||||
memset(cfg, 0, sizeof(*cfg));
|
||||
}
|
||||
|
||||
int __stoken_read_rcfile(const char *override, struct stoken_cfg *cfg,
|
||||
warn_fn_t warn_fn)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[BUFLEN];
|
||||
int linenum = 1, ret;
|
||||
|
||||
__stoken_zap_rcfile_data(cfg);
|
||||
|
||||
/* XXX: kind of dumb return code here, but it gets the job done */
|
||||
ret = fopen_rcfile(override, "r", warn_fn, &f);
|
||||
if (ret != ERR_NONE)
|
||||
return ERR_MISSING_PASSWORD;
|
||||
|
||||
while (fgets(buf, BUFLEN, f) != NULL) {
|
||||
int ret2 = parse_rcline(cfg, linenum++, buf, warn_fn);
|
||||
if (ret2 != ERR_NONE)
|
||||
ret = ret2;
|
||||
}
|
||||
|
||||
if (ferror(f)) {
|
||||
ret = ERR_GENERAL;
|
||||
warn_fn("rcfile: read error(s) were detected\n");
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (ret == ERR_NONE) {
|
||||
if (!cfg->rc_ver || !cfg->rc_token)
|
||||
return ERR_GENERAL;
|
||||
if (atoi(cfg->rc_ver) != RC_VER) {
|
||||
warn_fn("rcfile: version mismatch, ignoring contents\n");
|
||||
return ERR_TOKEN_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __stoken_write_rcfile(const char *override, const struct stoken_cfg *cfg,
|
||||
warn_fn_t warn_fn)
|
||||
{
|
||||
FILE *f;
|
||||
int ret;
|
||||
|
||||
ret = fopen_rcfile(override, "w", warn_fn, &f);
|
||||
if (ret != ERR_NONE)
|
||||
return ret;
|
||||
|
||||
if (cfg->rc_ver)
|
||||
fprintf(f, "version %s\n", cfg->rc_ver);
|
||||
if (cfg->rc_token)
|
||||
fprintf(f, "token %s\n", cfg->rc_token);
|
||||
if (cfg->rc_pin)
|
||||
fprintf(f, "pin %s\n", cfg->rc_pin);
|
||||
|
||||
if (ferror(f))
|
||||
ret = ERR_GENERAL;
|
||||
fclose(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void zap_current_token(struct stoken_ctx *ctx)
|
||||
{
|
||||
if (ctx->t) {
|
||||
free(ctx->t->v3);
|
||||
sdtid_free(ctx->t->sdtid);
|
||||
free(ctx->t);
|
||||
}
|
||||
ctx->t = NULL;
|
||||
}
|
||||
|
||||
static int clone_token(struct stoken_ctx *ctx, struct securid_token *tmp)
|
||||
{
|
||||
ctx->t = malloc(sizeof(*tmp));
|
||||
if (!ctx->t)
|
||||
return -EIO;
|
||||
memcpy(ctx->t, tmp, sizeof(*tmp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Exported functions
|
||||
***********************************************************************/
|
||||
|
||||
struct stoken_ctx *stoken_new(void)
|
||||
{
|
||||
struct stoken_ctx *ctx;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void stoken_destroy(struct stoken_ctx *ctx)
|
||||
{
|
||||
zap_current_token(ctx);
|
||||
__stoken_zap_rcfile_data(&ctx->cfg);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int stoken_import_rcfile(struct stoken_ctx *ctx, const char *path)
|
||||
{
|
||||
struct securid_token tmp;
|
||||
int rc;
|
||||
|
||||
zap_current_token(ctx);
|
||||
|
||||
rc = __stoken_read_rcfile(path, &ctx->cfg, &__stoken_warn_empty);
|
||||
if (rc == ERR_MISSING_PASSWORD)
|
||||
return -ENOENT;
|
||||
else if (rc != ERR_NONE)
|
||||
goto bad;
|
||||
|
||||
if (__stoken_parse_and_decode_token(ctx->cfg.rc_token, &tmp, 0) !=
|
||||
ERR_NONE)
|
||||
goto bad;
|
||||
|
||||
if (ctx->cfg.rc_pin) {
|
||||
if (tmp.flags & FL_PASSPROT)
|
||||
tmp.enc_pin_str = ctx->cfg.rc_pin;
|
||||
else {
|
||||
if (securid_pin_format_ok(ctx->cfg.rc_pin) == ERR_NONE)
|
||||
strncpy(tmp.pin, ctx->cfg.rc_pin,
|
||||
MAX_PIN + 1);
|
||||
else
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
return clone_token(ctx, &tmp);
|
||||
|
||||
bad:
|
||||
__stoken_zap_rcfile_data(&ctx->cfg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int stoken_import_string(struct stoken_ctx *ctx, const char *token_string)
|
||||
{
|
||||
struct securid_token tmp;
|
||||
|
||||
zap_current_token(ctx);
|
||||
|
||||
if (__stoken_parse_and_decode_token(token_string, &tmp, 0) != ERR_NONE)
|
||||
return -EINVAL;
|
||||
return clone_token(ctx, &tmp);
|
||||
}
|
||||
|
||||
struct stoken_info *stoken_get_info(struct stoken_ctx *ctx)
|
||||
{
|
||||
struct stoken_info *info = calloc(1, sizeof(*info));
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
strncpy(info->serial, ctx->t->serial, sizeof(info->serial) - 1);
|
||||
info->exp_date = securid_unix_exp_date(ctx->t);
|
||||
info->interval = securid_token_interval(ctx->t);
|
||||
info->token_version = ctx->t->version;
|
||||
info->uses_pin = securid_pin_required(ctx->t);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void stoken_pin_range(struct stoken_ctx *ctx, int *min_pin, int *max_pin)
|
||||
{
|
||||
*min_pin = MIN_PIN;
|
||||
*max_pin = MAX_PIN;
|
||||
}
|
||||
|
||||
int stoken_pin_required(struct stoken_ctx *ctx)
|
||||
{
|
||||
/* don't prompt for a PIN if it was saved in the rcfile */
|
||||
if (ctx->t->enc_pin_str || strlen(ctx->t->pin))
|
||||
return 0;
|
||||
return securid_pin_required(ctx->t);
|
||||
}
|
||||
|
||||
int stoken_pass_required(struct stoken_ctx *ctx)
|
||||
{
|
||||
return securid_pass_required(ctx->t);
|
||||
}
|
||||
|
||||
int stoken_devid_required(struct stoken_ctx *ctx)
|
||||
{
|
||||
return securid_devid_required(ctx->t);
|
||||
}
|
||||
|
||||
int stoken_check_pin(struct stoken_ctx *ctx, const char *pin)
|
||||
{
|
||||
return securid_pin_format_ok(pin) == ERR_NONE ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
const struct stoken_guid *stoken_get_guid_list(void)
|
||||
{
|
||||
return stoken_guid_list;
|
||||
}
|
||||
|
||||
int stoken_check_devid(struct stoken_ctx *ctx, const char *devid)
|
||||
{
|
||||
if (securid_check_devid(ctx->t, devid) == ERR_NONE)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int stoken_decrypt_seed(struct stoken_ctx *ctx, const char *pass,
|
||||
const char *devid)
|
||||
{
|
||||
if (securid_decrypt_seed(ctx->t, pass, devid) != ERR_NONE)
|
||||
return -EINVAL;
|
||||
if (ctx->t->enc_pin_str) {
|
||||
if (securid_decrypt_pin(ctx->t->enc_pin_str, pass,
|
||||
ctx->t->pin) != ERR_NONE)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *stoken_encrypt_seed(struct stoken_ctx *ctx, const char *pass,
|
||||
const char *devid)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (!ctx->t || !ctx->t->has_dec_seed)
|
||||
return NULL;
|
||||
ret = calloc(1, MAX_TOKEN_CHARS + 1);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
if (securid_encode_token(ctx->t, pass, devid, 2, ret) != ERR_NONE) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int stoken_compute_tokencode(struct stoken_ctx *ctx, time_t when,
|
||||
const char *pin, char *out)
|
||||
{
|
||||
if (securid_pin_required(ctx->t)) {
|
||||
if (pin && strlen(pin)) {
|
||||
if (securid_pin_format_ok(pin) != ERR_NONE)
|
||||
return -EINVAL;
|
||||
strncpy(ctx->t->pin, pin, MAX_PIN + 1);
|
||||
} else if (stoken_pin_required(ctx)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
securid_compute_tokencode(ctx->t, when, out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *stoken_format_tokencode(const char *tokencode)
|
||||
{
|
||||
int code_len = strlen(tokencode);
|
||||
char *str = malloc(code_len + 2);
|
||||
int i, j;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
for (i = 0, j = 0; i < code_len; i++) {
|
||||
if (i == code_len / 2)
|
||||
str[j++] = ' ';
|
||||
str[j++] = tokencode[i];
|
||||
}
|
||||
str[j] = 0;
|
||||
|
||||
return str;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* sdtid.h - SecurID sdtid/xml internal interfaces
|
||||
*
|
||||
* Copyright 2014 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __STOKEN_SDTID_H__
|
||||
#define __STOKEN_SDTID_H__
|
||||
|
||||
#include "stoken-internal.h"
|
||||
|
||||
struct securid_token;
|
||||
struct sdtid;
|
||||
|
||||
STOKEN_EXPORT int sdtid_decode(const char *in, struct securid_token *t);
|
||||
STOKEN_EXPORT int sdtid_decrypt(struct securid_token *t, const char *pass);
|
||||
STOKEN_EXPORT int sdtid_issue(const char *filename, const char *pass,
|
||||
const char *devid);
|
||||
STOKEN_EXPORT int sdtid_export(const char *filename, struct securid_token *t,
|
||||
const char *pass, const char *devid);
|
||||
STOKEN_EXPORT void sdtid_free(struct sdtid *s);
|
||||
|
||||
#endif /* __STOKEN_SDTID_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* securid.h - SecurID-related definitions
|
||||
*
|
||||
* Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __STOKEN_SECURID_H__
|
||||
#define __STOKEN_SECURID_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "stoken-internal.h"
|
||||
|
||||
#define AES_BLOCK_SIZE 16
|
||||
#define AES_KEY_SIZE 16
|
||||
|
||||
#define SHA256_BLOCK_SIZE 64
|
||||
#define SHA256_HASH_SIZE 32
|
||||
|
||||
#define MIN_PIN 4
|
||||
#define MAX_PIN 8
|
||||
|
||||
#define MAX_PASS 40
|
||||
#define MAGIC_LEN 6
|
||||
|
||||
#define VER_CHARS 1
|
||||
#define SERIAL_CHARS 12
|
||||
|
||||
#define CHECKSUM_BITS 15
|
||||
#define CHECKSUM_CHARS (CHECKSUM_BITS / TOKEN_BITS_PER_CHAR)
|
||||
|
||||
#define BINENC_BITS 189
|
||||
#define BINENC_CHARS (BINENC_BITS / TOKEN_BITS_PER_CHAR)
|
||||
|
||||
#define BINENC_OFS (VER_CHARS + SERIAL_CHARS)
|
||||
#define CHECKSUM_OFS (BINENC_OFS + BINENC_CHARS)
|
||||
|
||||
#define DEVID_CHARS 40
|
||||
|
||||
#define V3_DEVID_CHARS 48
|
||||
#define V3_NONCE_BYTES 16
|
||||
|
||||
#define TOKEN_BITS_PER_CHAR 3
|
||||
#define MIN_TOKEN_BITS 189
|
||||
#define MAX_TOKEN_BITS 255
|
||||
#define MAX_TOKEN_CHARS (MAX_TOKEN_BITS / TOKEN_BITS_PER_CHAR)
|
||||
#define MIN_TOKEN_CHARS ((MIN_TOKEN_BITS / TOKEN_BITS_PER_CHAR) + \
|
||||
SERIAL_CHARS + VER_CHARS + CHECKSUM_CHARS)
|
||||
|
||||
/*
|
||||
* This matches src/misc/base64/base64_encode.c in tomcrypt.
|
||||
* base64 produces 4 output characters (each carrying 6 bits of data) for
|
||||
* up to 3 input bytes (each carrying 8 bits of data). Plus one terminating
|
||||
* NUL at the end.
|
||||
*/
|
||||
#define BASE64_INPUT_LEN(x) ((4 * ((x) + 2) / 3) + 1)
|
||||
|
||||
/* decoded size (binary) */
|
||||
#define V3_BASE64_BYTES 0x123
|
||||
/* worst case, including terminating NUL */
|
||||
#define V3_BASE64_SIZE (BASE64_INPUT_LEN(V3_BASE64_BYTES))
|
||||
/* '+' and '/' expand to "%2B" and "%2F", so worst case... */
|
||||
#define V3_BASE64_URL_SIZE (3*BASE64_INPUT_LEN(V3_BASE64_BYTES))
|
||||
/* strlen() of smallest possible encoded size */
|
||||
#define V3_BASE64_MIN_CHARS (V3_BASE64_BYTES * 4 / 3)
|
||||
|
||||
#define BIT(x) (1 << (x))
|
||||
|
||||
#define FL_128BIT BIT(14)
|
||||
#define FL_PASSPROT BIT(13)
|
||||
#define FL_SNPROT BIT(12)
|
||||
#define FL_APPSEEDS BIT(11)
|
||||
#define FL_FEAT4 BIT(10)
|
||||
#define FL_TIMESEEDS BIT(9)
|
||||
#define FLD_DIGIT_SHIFT 6
|
||||
#define FLD_DIGIT_MASK (0x07 << FLD_DIGIT_SHIFT)
|
||||
#define FL_FEAT6 BIT(5)
|
||||
#define FLD_PINMODE_SHIFT 3
|
||||
#define FLD_PINMODE_MASK (0x03 << FLD_PINMODE_SHIFT)
|
||||
#define FLD_NUMSECONDS_SHIFT 0
|
||||
#define FLD_NUMSECONDS_MASK (0x03 << FLD_NUMSECONDS_SHIFT)
|
||||
|
||||
/* UNIX time_t for 2000/01/01 00:00:00 GMT */
|
||||
#define SECURID_EPOCH 946684800
|
||||
#define SECURID_EPOCH_DAYS (SECURID_EPOCH / (24*60*60))
|
||||
|
||||
/* V3 tokens use 1970/01/01 as the epoch, but each day has 337500 ticks */
|
||||
#define SECURID_V3_DAY 337500
|
||||
|
||||
/* Avoid 32-bit time_t overflows (January 2038) */
|
||||
#define MAX_TIME_T 0x7fffffff
|
||||
#define SECURID_MAX_SECS (MAX_TIME_T - SECURID_EPOCH)
|
||||
#define SECURID_MAX_DATE (SECURID_MAX_SECS / (24*60*60) - 1)
|
||||
|
||||
struct sdtid;
|
||||
struct v3_token;
|
||||
|
||||
struct securid_token {
|
||||
int version;
|
||||
char serial[SERIAL_CHARS + 1];
|
||||
uint16_t flags;
|
||||
uint16_t exp_date;
|
||||
int is_smartphone;
|
||||
|
||||
int has_enc_seed;
|
||||
uint8_t enc_seed[AES_KEY_SIZE];
|
||||
|
||||
uint16_t dec_seed_hash;
|
||||
uint16_t device_id_hash;
|
||||
|
||||
int has_dec_seed;
|
||||
uint8_t dec_seed[AES_KEY_SIZE];
|
||||
|
||||
int pinmode;
|
||||
char pin[MAX_PIN + 1];
|
||||
char *enc_pin_str;
|
||||
|
||||
struct sdtid *sdtid;
|
||||
int interactive;
|
||||
struct v3_token *v3;
|
||||
};
|
||||
|
||||
STOKEN_EXPORT int securid_decode_token(const char *in,
|
||||
struct securid_token *t);
|
||||
|
||||
STOKEN_EXPORT int securid_decrypt_seed(struct securid_token *t,
|
||||
const char *pass,
|
||||
const char *devid);
|
||||
|
||||
STOKEN_EXPORT int securid_check_devid(struct securid_token *t,
|
||||
const char *devid);
|
||||
|
||||
STOKEN_EXPORT void securid_compute_tokencode(struct securid_token *t,
|
||||
time_t now,
|
||||
char *code_out);
|
||||
|
||||
STOKEN_EXPORT void securid_token_info(const struct securid_token *t,
|
||||
void (*callback)(const char *key, const char *value));
|
||||
|
||||
STOKEN_EXPORT int securid_encode_token(const struct securid_token *t,
|
||||
const char *pass,
|
||||
const char *devid,
|
||||
int version,
|
||||
char *out);
|
||||
|
||||
STOKEN_EXPORT int securid_random_token(struct securid_token *t);
|
||||
STOKEN_EXPORT int securid_check_exp(struct securid_token *t, time_t now);
|
||||
STOKEN_EXPORT time_t securid_unix_exp_date(const struct securid_token *t);
|
||||
STOKEN_EXPORT int securid_token_interval(const struct securid_token *t);
|
||||
|
||||
STOKEN_EXPORT char *securid_encrypt_pin(const char *pin, const char *password);
|
||||
|
||||
STOKEN_EXPORT int securid_decrypt_pin(const char *enc_pin,
|
||||
const char *password,
|
||||
char *pin);
|
||||
|
||||
STOKEN_EXPORT int securid_pin_format_ok(const char *pin);
|
||||
STOKEN_EXPORT int securid_pin_required(const struct securid_token *t);
|
||||
STOKEN_EXPORT int securid_pass_required(const struct securid_token *t);
|
||||
STOKEN_EXPORT int securid_devid_required(const struct securid_token *t);
|
||||
STOKEN_EXPORT int securid_rand(void *out, int len, int paranoid);
|
||||
|
||||
#endif /* !__STOKEN_SECURID_H__ */
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* stc-nettle.c - stoken crypto wrappers for nettle
|
||||
*
|
||||
* Copyright 2014 Nikos Mavrogiannopoulos <nmav@redhat.com>
|
||||
* Copyright 2014 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nettle/aes.h>
|
||||
#include <nettle/base64.h>
|
||||
#include <nettle/bignum.h>
|
||||
#include <nettle/cbc.h>
|
||||
#include <nettle/hmac.h>
|
||||
#include <nettle/rsa.h>
|
||||
#include <nettle/sha.h>
|
||||
|
||||
#include "stoken-internal.h"
|
||||
|
||||
int stc_standalone_init(void)
|
||||
{
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
void stc_aes128_ecb_encrypt(const uint8_t *key, const uint8_t *in, uint8_t *out)
|
||||
{
|
||||
struct aes_ctx ctx;
|
||||
aes_set_encrypt_key(&ctx, 128/8, key);
|
||||
aes_encrypt(&ctx, AES_BLOCK_SIZE, out, in);
|
||||
}
|
||||
|
||||
void stc_aes128_ecb_decrypt(const uint8_t *key, const uint8_t *in, uint8_t *out)
|
||||
{
|
||||
struct aes_ctx ctx;
|
||||
aes_set_decrypt_key(&ctx, 128/8, key);
|
||||
aes_decrypt(&ctx, AES_BLOCK_SIZE, out, in);
|
||||
}
|
||||
|
||||
void stc_aes256_cbc_decrypt(const uint8_t *key, const uint8_t *in, int in_len,
|
||||
const uint8_t *iv, uint8_t *out)
|
||||
{
|
||||
struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE) ctx;
|
||||
aes_set_decrypt_key(&ctx.ctx, 256/8, key);
|
||||
CBC_SET_IV(&ctx, iv);
|
||||
CBC_DECRYPT(&ctx, aes_decrypt, in_len, out, in);
|
||||
}
|
||||
|
||||
void stc_aes256_cbc_encrypt(const uint8_t *key, const uint8_t *in, int in_len,
|
||||
const uint8_t *iv, uint8_t *out)
|
||||
{
|
||||
struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE) ctx;
|
||||
aes_set_encrypt_key(&ctx.ctx, 256/8, key);
|
||||
CBC_SET_IV(&ctx, iv);
|
||||
CBC_ENCRYPT(&ctx, aes_encrypt, in_len, out, in);
|
||||
}
|
||||
|
||||
void stc_sha1_hash(uint8_t *out, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct sha1_ctx md;
|
||||
|
||||
sha1_init(&md);
|
||||
va_start(ap, out);
|
||||
while (1) {
|
||||
const uint8_t *in = va_arg(ap, const uint8_t *);
|
||||
int in_len;
|
||||
|
||||
if (!in)
|
||||
break;
|
||||
in_len = va_arg(ap, int);
|
||||
sha1_update(&md, in_len, in);
|
||||
}
|
||||
va_end(ap);
|
||||
sha1_digest(&md, SHA1_DIGEST_SIZE, out);
|
||||
}
|
||||
|
||||
void stc_sha256_hash(uint8_t *out, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct sha256_ctx md;
|
||||
|
||||
sha256_init(&md);
|
||||
va_start(ap, out);
|
||||
while (1) {
|
||||
const uint8_t *in = va_arg(ap, const uint8_t *);
|
||||
int in_len;
|
||||
|
||||
if (!in)
|
||||
break;
|
||||
in_len = va_arg(ap, int);
|
||||
sha256_update(&md, in_len, in);
|
||||
}
|
||||
va_end(ap);
|
||||
sha256_digest(&md, SHA256_DIGEST_SIZE, out);
|
||||
}
|
||||
|
||||
int stc_b64_encode(const uint8_t *in, unsigned long len,
|
||||
uint8_t *out, unsigned long *outlen)
|
||||
{
|
||||
struct base64_encode_ctx ctx;
|
||||
unsigned size = 0;
|
||||
base64_encode_init(&ctx);
|
||||
|
||||
size = base64_encode_update(&ctx, out, len, in);
|
||||
size += base64_encode_final(&ctx, out+size);
|
||||
out[size] = 0;
|
||||
*outlen = size;
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
int stc_b64_decode(const uint8_t *in, unsigned long len,
|
||||
uint8_t *out, unsigned long *outlen)
|
||||
{
|
||||
struct base64_decode_ctx ctx;
|
||||
char tmp[BASE64_DECODE_LENGTH(len)];
|
||||
int ret;
|
||||
#ifdef NETTLE_OLD_BASE64_API
|
||||
unsigned dst_length = sizeof(tmp);
|
||||
#else
|
||||
size_t dst_length;
|
||||
#endif
|
||||
|
||||
base64_decode_init(&ctx);
|
||||
ret = base64_decode_update(&ctx, &dst_length, tmp, len, in);
|
||||
if (ret == 0) {
|
||||
return ERR_GENERAL;
|
||||
}
|
||||
|
||||
if (*outlen >= dst_length) {
|
||||
memcpy(out, tmp, dst_length);
|
||||
} else {
|
||||
return ERR_GENERAL;
|
||||
}
|
||||
*outlen = dst_length;
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
int stc_rsa_sha1_sign_digest(const uint8_t *privkey_der, size_t privkey_len,
|
||||
const uint8_t *digest,
|
||||
uint8_t *out, unsigned long *outlen)
|
||||
{
|
||||
struct rsa_private_key key;
|
||||
struct rsa_public_key pub;
|
||||
mpz_t msig;
|
||||
int ret;
|
||||
|
||||
rsa_private_key_init(&key);
|
||||
rsa_public_key_init(&pub);
|
||||
mpz_init(msig);
|
||||
|
||||
ret = rsa_keypair_from_der(&pub, &key, 1025,
|
||||
privkey_len - 1, privkey_der);
|
||||
if (ret == 0) {
|
||||
ret = ERR_GENERAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = rsa_sha1_sign_digest(&key, digest, msig);
|
||||
if (ret == 0) {
|
||||
ret = ERR_GENERAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
nettle_mpz_get_str_256(nettle_mpz_sizeinbase_256_u(msig), out, msig);
|
||||
ret = ERR_NONE;
|
||||
|
||||
cleanup:
|
||||
rsa_private_key_clear(&key);
|
||||
rsa_public_key_clear(&pub);
|
||||
mpz_clear(msig);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* stc-tomcrypt.c - stoken crypto wrappers for libtomcrypt
|
||||
*
|
||||
* Copyright 2014 Nikos Mavrogiannopoulos <nmav@redhat.com>
|
||||
* Copyright 2014 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tomcrypt.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "stoken-internal.h"
|
||||
|
||||
/* These are redundant, but stc-* files shouldn't include securid.h */
|
||||
#define AES_BLOCK_SIZE 16
|
||||
#define AES_KEY_SIZE 16
|
||||
#define AES256_KEY_SIZE 32
|
||||
|
||||
/* Backwards compatibility support for pre-1.18 versions of libtomcrypt */
|
||||
#ifdef LIBTOMCRYPT_OLD_PKCS_NAMES
|
||||
#define LTC_PKCS_1_V1_5 LTC_LTC_PKCS_1_V1_5
|
||||
#endif
|
||||
|
||||
int stc_standalone_init(void)
|
||||
{
|
||||
/* libtomcrypt init for sdtid BatchSignature generation */
|
||||
ltc_mp = ltm_desc;
|
||||
if (register_hash(&sha1_desc) == -1)
|
||||
return ERR_GENERAL;
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
void stc_aes128_ecb_encrypt(const uint8_t *key, const uint8_t *in, uint8_t *out)
|
||||
{
|
||||
symmetric_key skey;
|
||||
uint8_t tmp[AES_BLOCK_SIZE];
|
||||
|
||||
/* these shouldn't allocate memory or fail */
|
||||
if (rijndael_setup(key, AES_KEY_SIZE, 0, &skey) != CRYPT_OK ||
|
||||
rijndael_ecb_encrypt(in, tmp, &skey) != CRYPT_OK)
|
||||
abort();
|
||||
rijndael_done(&skey);
|
||||
|
||||
/* in case "in" and "out" point to the same buffer */
|
||||
memcpy(out, tmp, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
void stc_aes128_ecb_decrypt(const uint8_t *key, const uint8_t *in, uint8_t *out)
|
||||
{
|
||||
symmetric_key skey;
|
||||
uint8_t tmp[AES_BLOCK_SIZE];
|
||||
|
||||
if (rijndael_setup(key, AES_KEY_SIZE, 0, &skey) != CRYPT_OK ||
|
||||
rijndael_ecb_decrypt(in, tmp, &skey) != CRYPT_OK)
|
||||
abort();
|
||||
rijndael_done(&skey);
|
||||
|
||||
memcpy(out, tmp, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
void stc_aes256_cbc_decrypt(const uint8_t *key, const uint8_t *in, int in_len,
|
||||
const uint8_t *iv, uint8_t *out)
|
||||
{
|
||||
symmetric_key skey;
|
||||
int i, j;
|
||||
uint8_t local_iv[AES_BLOCK_SIZE];
|
||||
|
||||
rijndael_setup(key, AES256_KEY_SIZE, 0, &skey);
|
||||
|
||||
memcpy(local_iv, iv, AES_BLOCK_SIZE);
|
||||
for (i = 0; i < in_len; i += AES_BLOCK_SIZE) {
|
||||
rijndael_ecb_decrypt(in, out, &skey);
|
||||
for (j = 0; j < AES_BLOCK_SIZE; j++)
|
||||
out[j] ^= local_iv[j];
|
||||
memcpy(local_iv, in, AES_BLOCK_SIZE);
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
rijndael_done(&skey);
|
||||
}
|
||||
|
||||
void stc_aes256_cbc_encrypt(const uint8_t *key, const uint8_t *in, int in_len,
|
||||
const uint8_t *iv, uint8_t *out)
|
||||
{
|
||||
symmetric_key skey;
|
||||
int i, j;
|
||||
uint8_t xored_in[AES_BLOCK_SIZE];
|
||||
|
||||
rijndael_setup(key, AES256_KEY_SIZE, 0, &skey);
|
||||
|
||||
for (i = 0; i < in_len; i += AES_BLOCK_SIZE) {
|
||||
for (j = 0; j < AES_BLOCK_SIZE; j++) {
|
||||
xored_in[j] = in[j] ^
|
||||
(i ? out[j - AES_BLOCK_SIZE] : iv[j]);
|
||||
}
|
||||
rijndael_ecb_encrypt(xored_in, out, &skey);
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
rijndael_done(&skey);
|
||||
}
|
||||
|
||||
void stc_sha1_hash(uint8_t *out, ...)
|
||||
{
|
||||
va_list ap;
|
||||
hash_state md;
|
||||
|
||||
sha1_init(&md);
|
||||
va_start(ap, out);
|
||||
while (1) {
|
||||
const uint8_t *in = va_arg(ap, const uint8_t *);
|
||||
int in_len;
|
||||
|
||||
if (!in)
|
||||
break;
|
||||
in_len = va_arg(ap, int);
|
||||
sha1_process(&md, in, in_len);
|
||||
}
|
||||
va_end(ap);
|
||||
sha1_done(&md, out);
|
||||
}
|
||||
|
||||
void stc_sha256_hash(uint8_t *out, ...)
|
||||
{
|
||||
va_list ap;
|
||||
hash_state md;
|
||||
|
||||
sha256_init(&md);
|
||||
va_start(ap, out);
|
||||
while (1) {
|
||||
const uint8_t *in = va_arg(ap, const uint8_t *);
|
||||
int in_len;
|
||||
|
||||
if (!in)
|
||||
break;
|
||||
in_len = va_arg(ap, int);
|
||||
sha256_process(&md, in, in_len);
|
||||
}
|
||||
va_end(ap);
|
||||
sha256_done(&md, out);
|
||||
}
|
||||
|
||||
int stc_b64_encode(const uint8_t *in, unsigned long len,
|
||||
uint8_t *out, unsigned long *outlen)
|
||||
{
|
||||
return base64_encode(in, len, out, outlen) == CRYPT_OK ?
|
||||
ERR_NONE : ERR_GENERAL;
|
||||
}
|
||||
|
||||
int stc_b64_decode(const uint8_t *in, unsigned long len,
|
||||
uint8_t *out, unsigned long *outlen)
|
||||
{
|
||||
return base64_decode(in, len, out, outlen) == CRYPT_OK ?
|
||||
ERR_NONE : ERR_GENERAL;
|
||||
}
|
||||
|
||||
int stc_rsa_sha1_sign_digest(const uint8_t *privkey_der, size_t privkey_len,
|
||||
const uint8_t *digest,
|
||||
uint8_t *out, unsigned long *outlen)
|
||||
{
|
||||
int hash_idx, rc = ERR_NONE;
|
||||
rsa_key key;
|
||||
|
||||
/*
|
||||
* NOTE: This is set up in common.c. If we ever decide to let library
|
||||
* callers generate sdtid files, we will have to figure out how to
|
||||
* call register_sha1() and set ltc_mp without disturbing other
|
||||
* libtomcrypt users who might coexist in the same process.
|
||||
*/
|
||||
hash_idx = find_hash("sha1");
|
||||
if (hash_idx < 0)
|
||||
return ERR_GENERAL;
|
||||
|
||||
if (rsa_import(privkey_der, privkey_len, &key) != CRYPT_OK)
|
||||
return ERR_GENERAL;
|
||||
if (rsa_sign_hash_ex(digest, (160 / 8), out, outlen,
|
||||
LTC_PKCS_1_V1_5, NULL, 0,
|
||||
hash_idx, 0, &key) != CRYPT_OK)
|
||||
rc = ERR_GENERAL;
|
||||
|
||||
rsa_free(&key);
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* stoken-internal.h - internal functions called within the stoken package
|
||||
*
|
||||
* Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __STOKEN_INTERNAL_H__
|
||||
#define __STOKEN_INTERNAL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "stoken.h"
|
||||
|
||||
#define BUFLEN 2048
|
||||
#define RC_NAME ".stokenrc"
|
||||
#define RC_VER 1
|
||||
|
||||
struct stoken_cfg {
|
||||
char *rc_ver;
|
||||
char *rc_token;
|
||||
char *rc_pin;
|
||||
};
|
||||
|
||||
struct securid_token;
|
||||
|
||||
/* keep this in sync with stoken_errstr */
|
||||
enum {
|
||||
ERR_NONE = 0,
|
||||
ERR_GENERAL,
|
||||
ERR_BAD_LEN,
|
||||
ERR_TOKEN_VERSION,
|
||||
ERR_CHECKSUM_FAILED,
|
||||
ERR_BAD_PASSWORD,
|
||||
ERR_MISSING_PASSWORD,
|
||||
ERR_DECRYPT_FAILED,
|
||||
ERR_BAD_DEVID,
|
||||
ERR_NO_MEMORY,
|
||||
ERR_FILE_READ,
|
||||
ERR_MULTIPLE_TOKENS,
|
||||
};
|
||||
|
||||
typedef void (warn_fn_t)(const char *, ...);
|
||||
static inline void __stoken_warn_empty(const char *fmt, ...) { }
|
||||
|
||||
STOKEN_EXPORT int __stoken_parse_and_decode_token(const char *str,
|
||||
struct securid_token *t,
|
||||
int interactive);
|
||||
|
||||
STOKEN_EXPORT int __stoken_read_rcfile(const char *override,
|
||||
struct stoken_cfg *cfg,
|
||||
warn_fn_t warn_fn);
|
||||
|
||||
STOKEN_EXPORT int __stoken_write_rcfile(const char *override,
|
||||
const struct stoken_cfg *cfg,
|
||||
warn_fn_t warn_fn);
|
||||
|
||||
STOKEN_EXPORT void __stoken_zap_rcfile_data(struct stoken_cfg *cfg);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
/* Sigh. This exists but it isn't in the Bionic headers. */
|
||||
int mkstemps(char *path, int slen);
|
||||
#elif !defined(HAVE_MKSTEMPS)
|
||||
#define mkstemps stoken__mkstemps
|
||||
STOKEN_EXPORT int stoken__mkstemps(char *path, int slen);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRCASESTR
|
||||
#define strcasestr stoken__strcasestr
|
||||
STOKEN_EXPORT char *stoken__strcasestr(const char *haystack,
|
||||
const char *needle);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GMTIME_R
|
||||
#define gmtime_r stoken__gmtime_r
|
||||
struct tm *stoken__gmtime_r(const time_t *timep, struct tm *result);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_TIMEGM
|
||||
#define timegm stoken__timegm
|
||||
time_t stoken__timegm(struct tm *tm);
|
||||
#endif
|
||||
|
||||
/* crypto wrappers */
|
||||
STOKEN_EXPORT int stc_standalone_init(void);
|
||||
void stc_aes128_ecb_decrypt(const uint8_t *key, const uint8_t *in, uint8_t *out);
|
||||
void stc_aes128_ecb_encrypt(const uint8_t *key, const uint8_t *in, uint8_t *out);
|
||||
void stc_aes256_cbc_decrypt(const uint8_t *key, const uint8_t *in, int in_len,
|
||||
const uint8_t *iv, uint8_t *out);
|
||||
void stc_aes256_cbc_encrypt(const uint8_t *key, const uint8_t *in, int in_len,
|
||||
const uint8_t *iv, uint8_t *out);
|
||||
void stc_sha1_hash(uint8_t *out, ...);
|
||||
void stc_sha256_hash(uint8_t *out, ...);
|
||||
int stc_b64_encode(const uint8_t *in, unsigned long len,
|
||||
uint8_t *out, unsigned long *outlen);
|
||||
int stc_b64_decode(const uint8_t *in, unsigned long len,
|
||||
uint8_t *out, unsigned long *outlen);
|
||||
int stc_rsa_sha1_sign_digest(const uint8_t *privkey_der, size_t privkey_len,
|
||||
const uint8_t *digest,
|
||||
uint8_t *out, unsigned long *outlen);
|
||||
|
||||
#endif /* !__STOKEN_INTERNAL_H__ */
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* stoken.h - public libstoken library interface
|
||||
*
|
||||
* Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __STOKEN_H__
|
||||
#define __STOKEN_H__
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define STOKEN_API_VER_MAJOR 1
|
||||
#define STOKEN_API_VER_MINOR 3
|
||||
|
||||
/* Before API version 1.3 (stoken 0.8) this macro didn't exist.
|
||||
* Somewhat ironic, that the API version check itself needs to be
|
||||
* conditionally used depending on the API version. A very simple way
|
||||
* for users to handle this with an approximately correct answer is
|
||||
* #include <stoken.h>
|
||||
* #ifndef STOKEN_CHECK_VER
|
||||
* #define STOKEN_CHECK_VER(x,y) 0
|
||||
* #endif
|
||||
*/
|
||||
#define STOKEN_CHECK_VER(maj, min) \
|
||||
(STOKEN_API_VER_MAJOR > (maj) || \
|
||||
(STOKEN_API_VER_MAJOR == (maj) && \
|
||||
STOKEN_API_VER_MINOR >= (min)))
|
||||
|
||||
#define STOKEN_MAX_TOKENCODE 8
|
||||
|
||||
#if defined(_WIN32) && defined(LIBSTOKEN_BUILD)
|
||||
#define STOKEN_EXPORT __declspec(dllexport)
|
||||
#elif defined(_WIN32)
|
||||
#define STOKEN_EXPORT __declspec(dllimport)
|
||||
#else
|
||||
#define STOKEN_EXPORT
|
||||
#endif
|
||||
|
||||
struct stoken_ctx;
|
||||
|
||||
struct stoken_info {
|
||||
char serial[16];
|
||||
time_t exp_date;
|
||||
int interval;
|
||||
int token_version;
|
||||
int uses_pin;
|
||||
};
|
||||
|
||||
struct stoken_guid {
|
||||
const char *tag;
|
||||
const char *long_name;
|
||||
const char *guid;
|
||||
};
|
||||
|
||||
/*
|
||||
* Create/destroy library context.
|
||||
* stoken_new() returns NULL on error.
|
||||
*/
|
||||
STOKEN_EXPORT struct stoken_ctx *stoken_new(void);
|
||||
STOKEN_EXPORT void stoken_destroy(struct stoken_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Load a token from an existing .stokenrc file (PATH can be NULL to use
|
||||
* $HOME/.stokenrc).
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* 0: success; token is now stored in CTX
|
||||
* -ENOENT: missing input file
|
||||
* -EINVAL: invalid input file format
|
||||
* -EIO: any other failure (e.g. ran out of memory)
|
||||
*/
|
||||
STOKEN_EXPORT int stoken_import_rcfile(struct stoken_ctx *ctx,
|
||||
const char *path);
|
||||
|
||||
/*
|
||||
* Parse a token string (nominally a string of ~71 digits, starting with
|
||||
* '1' or '2').
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* 0: success; token is now stored in CTX
|
||||
* -EINVAL: invalid input string format
|
||||
* -EIO: any other failure (e.g. ran out of memory)
|
||||
*/
|
||||
STOKEN_EXPORT int stoken_import_string(struct stoken_ctx *ctx,
|
||||
const char *token_string);
|
||||
|
||||
/*
|
||||
* Retrieve metadata for the currently imported token. This returns a
|
||||
* callee-allocated, caller-freed struct, which may grow larger in the future.
|
||||
*
|
||||
* In general this should be called after stoken_decrypt_seed(), as
|
||||
* most of the token metadata is encrypted with the devid and/or password on
|
||||
* v3 tokens.
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* ptr: success
|
||||
* NULL: any failure (e.g. ran out of memory)
|
||||
*/
|
||||
STOKEN_EXPORT struct stoken_info *stoken_get_info(struct stoken_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Set *MIN_PIN and *MAX_PIN to reflect the valid range of PIN lengths
|
||||
* (e.g. 4-8).
|
||||
*/
|
||||
STOKEN_EXPORT void stoken_pin_range(struct stoken_ctx *ctx,
|
||||
int *min_pin,
|
||||
int *max_pin);
|
||||
|
||||
/*
|
||||
* Returns nonzero if the token in CTX requires a PIN, and doesn't have one
|
||||
* saved (i.e. you need to prompt for it). stoken_info->uses_pin returns
|
||||
* nonzero if a PIN is used in the calculation. If stoken_info->uses_pin is
|
||||
* 0, a PIN is not needed to generate the tokencode but you may need to
|
||||
* request and concatenate a PIN in order to log in to a protected resource:
|
||||
* PASSCODE = PIN + TOKENCODE
|
||||
*/
|
||||
STOKEN_EXPORT int stoken_pin_required(struct stoken_ctx *ctx);
|
||||
|
||||
/* returns nonzero if the token in CTX needs a password to decrypt the seed */
|
||||
STOKEN_EXPORT int stoken_pass_required(struct stoken_ctx *ctx);
|
||||
|
||||
/* returns nonzero if the token in CTX needs a device ID to decrypt the seed */
|
||||
STOKEN_EXPORT int stoken_devid_required(struct stoken_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Check the PIN for proper format. This does not validate whether the PIN
|
||||
* matches the PIN on file for the user's account; only the server knows that.
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* 0: success
|
||||
* -EINVAL: invalid format
|
||||
*/
|
||||
STOKEN_EXPORT int stoken_check_pin(struct stoken_ctx *ctx, const char *pin);
|
||||
|
||||
/*
|
||||
* Obtain the list of known "class GUIDs" used to bind a token to a specific
|
||||
* type of device (e.g. iPhone).
|
||||
*/
|
||||
STOKEN_EXPORT const struct stoken_guid *stoken_get_guid_list(void);
|
||||
|
||||
/*
|
||||
* Check the device ID by performing a partial seed decrypt. This helps
|
||||
* callers provide better user feedback after a stoken_decrypt_seed() failure.
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* 0: success
|
||||
* -EINVAL: DEVID MAC failed
|
||||
* -EIO: any other failure (e.g. ran out of memory)
|
||||
*/
|
||||
STOKEN_EXPORT int stoken_check_devid(struct stoken_ctx *ctx,
|
||||
const char *devid);
|
||||
|
||||
/*
|
||||
* Try to decrypt the seed stored in CTX, and compare the MAC to see if
|
||||
* decryption was successful.
|
||||
*
|
||||
* PASS may be NULL if stoken_needs_pass() == 0
|
||||
* DEVID may be NULL if stoken_needs_devid() == 0
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* 0: success
|
||||
* -EINVAL: MAC failed (PASS or DEVID is probably incorrect)
|
||||
* -EIO: any other failure (e.g. ran out of memory)
|
||||
*/
|
||||
STOKEN_EXPORT int stoken_decrypt_seed(struct stoken_ctx *ctx,
|
||||
const char *pass,
|
||||
const char *devid);
|
||||
|
||||
/*
|
||||
* Generate a new token string for the previously-decrypted seed stored
|
||||
* in CTX. PASS and DEVID may be NULL. The returned string must be freed
|
||||
* by the caller.
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* ptr: on success, a pointer to a new string
|
||||
* NULL: on failure
|
||||
*/
|
||||
STOKEN_EXPORT char *stoken_encrypt_seed(struct stoken_ctx *ctx,
|
||||
const char *pass,
|
||||
const char *devid);
|
||||
|
||||
/*
|
||||
* Generate a tokencode from the decrypted seed, for UNIX time WHEN.
|
||||
* OUT is allocated by the caller, and must be able to store at least
|
||||
* (STOKEN_MAX_TOKENCODE + 1) bytes.
|
||||
*
|
||||
* This can be called over and over again, as needed.
|
||||
*
|
||||
* If stoken_pin_required() returns 0, PIN may be NULL. If PIN is not
|
||||
* NULL and the user stored a PIN in ~/.stokenrc, the PIN string passed
|
||||
* into this function will override the stored PIN. This will affect
|
||||
* subsequent calls to stoken_compute_tokencode() but the change will not
|
||||
* be stored on disk.
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* 0: success
|
||||
* -EINVAL: invalid PIN format
|
||||
* -EIO: general failure
|
||||
*/
|
||||
STOKEN_EXPORT int stoken_compute_tokencode(struct stoken_ctx *ctx,
|
||||
time_t when,
|
||||
const char *pin,
|
||||
char *out);
|
||||
|
||||
/*
|
||||
* Inject a space in the middle of the code, e.g. "1234 5678".
|
||||
* Typical libstoken users would use the formatted tokencode for display
|
||||
* purposes only, and use the unformatted tokencode for "copy to clipboard",
|
||||
* pasting into login forms, etc.
|
||||
*
|
||||
* The returned string must be freed by the caller. Returns NULL on malloc
|
||||
* failure.
|
||||
*/
|
||||
STOKEN_EXPORT char *stoken_format_tokencode(const char *tokencode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !__STOKEN_H__ */
|
|
@ -0,0 +1,71 @@
|
|||
.\"
|
||||
.\" Man page for stoken-gui
|
||||
.\"
|
||||
.TH stoken-gui 1 2012-09-09
|
||||
.nh
|
||||
.SH NAME
|
||||
stoken-gui \- GTK+ software token
|
||||
.SH SYNOPSIS
|
||||
\fBstoken-gui\fP [\fIopts\fP]
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fBstoken-gui\fP is a software token compatible with RSA SecurID 128-bit (AES)
|
||||
tokens. The graphical user interface provides limited support for password
|
||||
entry and viewing the current token. Initial token importation and other
|
||||
configuration items are handled through the command-line interface,
|
||||
\fBstoken(1)\fP.
|
||||
.PP
|
||||
After using \fBstoken import\fP to populate \fI~/.stokenrc\fP,
|
||||
\fBstoken-gui\fP may be invoked to display the tokencode and counter. The
|
||||
tokencode changes once a minute; \fBstoken-gui\fP may be left running
|
||||
forever and will copy the current tokencode to the clipboard on demand.
|
||||
.PP
|
||||
If a password and/or PIN is required, \fBstoken-gui\fP will pop up a
|
||||
dialog box requesting the appropriate information.
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
\fB\-\-small\fP
|
||||
Show a minimal window that only displays a tokencode and a progress bar.
|
||||
Clicking on the tokencode copies it to the clipboard.
|
||||
.TP
|
||||
\fB\-\-rcfile=\fIfile\fP
|
||||
Use an alternate \fI.stokenrc\fP file. This is typically used to support
|
||||
multiple tokens on the same user account.
|
||||
.TP
|
||||
\fB\-\-password=\fIpassword\fP, \fB\-p\fP \fIpassword\fP
|
||||
Use a password supplied from the command line, instead of prompting the user.
|
||||
See notes in \fBSECURITY CONSIDERATIONS\fP on the \fBstoken(1)\fP man page.
|
||||
.TP
|
||||
\fB\-\-pin=\fIpin\fP, \fB\-n\fP \fIpin\fP
|
||||
Use a PIN supplied from the command line, instead of prompting the user.
|
||||
See notes in \fBSECURITY CONSIDERATIONS\fP on the \fBstoken(1)\fP man page.
|
||||
.TP
|
||||
\fB\-\-force\fP, \fB\-f\fP
|
||||
Override token expiration date check.
|
||||
.TP
|
||||
\fB\-\-file=\fIfile\fP
|
||||
Use a token from \fIfile\fP instead of the \fI.stokenrc\fP file. For
|
||||
testing purposes only.
|
||||
.TP
|
||||
\fB\-\-token=\fItoken_string\fP
|
||||
Use a token from the command line instead of the \fI.stokenrc\fP file. See
|
||||
above notes on \fB\-\-file\fP.
|
||||
.TP
|
||||
\fB\-\-random\fP
|
||||
Generate a random token on the fly. Used for testing or demonstrations only.
|
||||
These tokens should \fBnot\fP be used for real authentication.
|
||||
.TP
|
||||
\fB\-\-help\fP, \fB\-h\fP
|
||||
Display basic usage information.
|
||||
.TP
|
||||
\fB\-\-version\fP, \fB\-v\fP
|
||||
Display version information.
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
\fBstoken\fP(1).
|
||||
.SH FILES
|
||||
.TP
|
||||
~/.stokenrc
|
||||
Default configuration file.
|
||||
.SH "AUTHOR"
|
||||
Kevin Cernekee <cernekee@gmail.com>
|
|
@ -0,0 +1,335 @@
|
|||
.\"
|
||||
.\" Man page for stoken
|
||||
.\"
|
||||
.TH stoken 1 2012-09-09
|
||||
.nh
|
||||
.SH NAME
|
||||
stoken \- software token for cryptographic authentication
|
||||
.SH SYNOPSIS
|
||||
\fBstoken\fP [\fBtokencode\fP] [\fB\-\-stdin\fP] [\fB\-\-force\fP]
|
||||
[\fB\-\-next\fP] [\fIopts\fP]
|
||||
.PP
|
||||
\fBstoken\fP \fBimport\fP
|
||||
{\fB\-\-file=\fP\fIfile\fP | \fB\-\-token=\fP\fItoken_string\fP}
|
||||
[\fB\-\-force\fP] [\fIopts\fP]
|
||||
.PP
|
||||
\fBstoken\fP \fBsetpin\fP [\fIopts\fP]
|
||||
.PP
|
||||
\fBstoken\fP \fBsetpass\fP [\fIopts\fP]
|
||||
.PP
|
||||
\fBstoken\fP \fBshow\fP [\fB\-\-seed\fP] [\fIopts\fP]
|
||||
.PP
|
||||
\fBstoken\fP \fBexport\fP
|
||||
[{\fB\-\-blocks\fP | \fB\-\-iphone\fP | \fB\-\-android\fP | \fB\-\-v3\fP |
|
||||
\fB\-\-sdtid\fP | \fB\-\-qr=\fP\fIfile.png\fP | \fB\-\-show\-qr\fP}]
|
||||
[\fIopts\fP]
|
||||
.PP
|
||||
\fBstoken\fP \fBissue\fP [\-\-\fBtemplate\fP=\fIfile\fP]
|
||||
.PP
|
||||
\fBstoken\fP \fBhelp\fP
|
||||
.PP
|
||||
\fBstoken\fP \fBversion\fP
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fBstoken\fP is a software token compatible with RSA SecurID 128-bit (AES)
|
||||
tokens. The command-line interface provides facilities for importing new
|
||||
tokens, displaying the current tokencode, encrypting the seed with a
|
||||
user-specified password, storing the user's PIN alongside the token, and
|
||||
viewing or exporting the token data.
|
||||
.SH "BASIC USAGE"
|
||||
.PP
|
||||
Use \fBstoken import\fP to decode a token string and write it into
|
||||
\fI~/.stokenrc\fP. This may prompt for a device ID and/or password,
|
||||
depending on what options your administrator used to create the token.
|
||||
The token string can be provided on the command line, or read from a
|
||||
text file.
|
||||
.PP
|
||||
\fBstoken\fP will autodetect the following types of token strings:
|
||||
.TP
|
||||
.B 286510182209303756117707012447003320623006...
|
||||
.PD 0
|
||||
.TP
|
||||
.B 29658\-21098\-45467\-64675\-65731\-01441\-11337...
|
||||
.PD
|
||||
Pure numeric (81-digit) "ctf" (compressed token format) strings, with or
|
||||
without dashes. These may have been furnished as-is, or they could have
|
||||
been derived from an \fIsdtid\fP file by the RSA \fITokenConverter\fP program.
|
||||
.TP
|
||||
.B com.rsa.securid.iphone://ctf?ctfData=229639330774927764401...
|
||||
iPhone-compatible token strings.
|
||||
.TP
|
||||
.B http://127.0.0.1/securid/ctf?ctfData=250494932146245277466...
|
||||
.PD 0
|
||||
.TP
|
||||
.B http://127.0.0.1/securid/ctf?ctfData=AwAAfBc3QSopPxxjLGnxf...
|
||||
Android-compatible token strings.
|
||||
.PD
|
||||
.TP
|
||||
.B <?xml version=...
|
||||
RSA \fIsdtid\fP-formatted XML files. These should be imported from a file:
|
||||
\fBstoken import \-\-file=FILE.SDTID\fP.
|
||||
.PD
|
||||
.PP
|
||||
Tokens supplied as QR codes can be converted back to standard URIs by running
|
||||
\fBzbarimg\fP(1) on the image file.
|
||||
.PP
|
||||
The device ID, if used, can be viewed in the "about" menu for the RSA soft
|
||||
token app on the phone. Numeric ctf strings and smartphone tokens bound
|
||||
to a device ID contain a seed that is encrypted using the device ID, so the
|
||||
ID must be furnished before stoken can successfully import the token.
|
||||
\fIsdtid\fP files can be imported without knowledge of the device ID, as
|
||||
long as the password (if any) is known.
|
||||
.PP
|
||||
By default, \fBstoken import\fP will refuse to overwrite an existing token in
|
||||
\fI~/.stokenrc\fP. The \fB\-\-force\fP switch overrides this check.
|
||||
.PP
|
||||
\fBstoken import\fP will normally prompt for a new password, which is used
|
||||
to encrypt the seed before storing it in \fI~/.stokenrc\fP. This can be
|
||||
bypassed by entering an empty password, or specifying
|
||||
\fB\-\-new\-password=''\fP on the command line. It is recommended to
|
||||
choose a longer, hard-to-guess passphrase for this purpose.
|
||||
.PP
|
||||
After a token has been imported, running \fBstoken\fP with no arguments
|
||||
will prompt for any required password or PIN, then display the current
|
||||
tokencode.
|
||||
.PP
|
||||
Tokencodes are computed from the raw (decrypted) seed data, the current
|
||||
time of day, and the PIN. If the same seed is installed on multiple
|
||||
devices, they should all produce identical tokencodes. If they do not,
|
||||
double-check the timezone setting and consider using NTP to synchronize
|
||||
the system time to a known good source.
|
||||
.PP
|
||||
\fBstoken setpin\fP can be used to save the PIN in \fI~/.stokenrc\fP.
|
||||
Not all tokens will require a PIN; this can be configured by the SecurID
|
||||
administrator when generating new tokens. Setting an empty PIN will remove
|
||||
the PIN from \fI~/.stokenrc\fP so that the user will be prompted every
|
||||
time it is required. See the \fBSECURITY CONSIDERATIONS\fP section below
|
||||
for additional details.
|
||||
.PP
|
||||
\fBstoken setpass\fP encrypts the seed and PIN (if present) in
|
||||
\fI~/.stokenrc\fP with a user-selectable password or passphrase. If an
|
||||
empty password is entered, the password will be removed. See the
|
||||
\fBSECURITY CONSIDERATIONS\fP section below for additional details.
|
||||
.SH "VIEWING TOKENS"
|
||||
.PP
|
||||
\fBstoken show\fP displays information about the current token, typically
|
||||
read from \fI~/.stokenrc\fP. The \fB\-\-seed\fP option displays the
|
||||
encrypted and decrypted seed bytes (which should be treated as sensitive
|
||||
data, as they can be used to derive tokencodes).
|
||||
.PP
|
||||
\fBstoken export\fP translates the current token into a format suitable
|
||||
for importation to another device.
|
||||
.PP
|
||||
\fBstoken issue\fP generates a new software token in XML \fIsdtid\fP
|
||||
format. A template file, itself in \fIsdtid\fP format, may be
|
||||
provided to override some or all of the human-readable fields. This would
|
||||
permit appropriate serial numbers, expiration dates, usernames, etc. to be
|
||||
specified. If Secret, Seed, or MAC fields are present in the template
|
||||
file, they will be ignored.
|
||||
.SH "GLOBAL OPTIONS"
|
||||
.TP
|
||||
\fB\-\-rcfile=\fIfile\fP
|
||||
Use an alternate \fI.stokenrc\fP configuration file. This is typically
|
||||
used to support multiple tokens on the same user's UNIX account. Note that
|
||||
the \fI.stokenrc\fP file stores additional data (such as the PIN), so it
|
||||
cannot be parsed as a "raw" token string by \fBstoken \-\-file\fP.
|
||||
.TP
|
||||
\fB\-\-password=\fIpassword\fP, \fB\-p\fP \fIpassword\fP
|
||||
Use a password supplied from the command line, instead of prompting the user.
|
||||
See notes in \fBSECURITY CONSIDERATIONS\fP below.
|
||||
.TP
|
||||
\fB\-\-pin=\fIpin\fP, \fB\-n\fP \fIpin\fP
|
||||
Use a PIN supplied from the command line, instead of prompting the user.
|
||||
See notes in \fBSECURITY CONSIDERATIONS\fP below. If you save your PIN
|
||||
in \fI~/.stokenrc\fP, note that \fB\-\-pin=0000\fP is often required when
|
||||
activating a new soft token for the first time.
|
||||
.TP
|
||||
\fB\-\-devid=\fIdevid\fP
|
||||
Use a device ID supplied from the command line to decrypt the token. A
|
||||
token can be bound to a class GUID device ID (i.e. a certain type of device,
|
||||
such as "iPhone" or "Android"), a unique device ID (one specific unit), or
|
||||
nothing. \fBstoken\fP will attempt to autodetect matches with a class GUID,
|
||||
but on rare occasions this results in false positives due to hash collisions.
|
||||
In these cases, the bound device ID should be specified on the command line to
|
||||
override autodetection.
|
||||
.SH "EXPORT OPTIONS"
|
||||
.TP
|
||||
\fB\-\-new\-password=\fIpassword\fP
|
||||
Supply the encryption password from the command line for operations that
|
||||
write out a token string or \fI.stokenrc\fP file: \fBimport\fP, \fBexport\fP,
|
||||
\fBsetpass\fP, and \fBissue\fP. See notes in \fBSECURITY CONSIDERATIONS\fP
|
||||
below.
|
||||
.TP
|
||||
\fB\-\-keep\-password\fP
|
||||
If the token in the \fI.stokenrc\fP file is protected with a password, retain
|
||||
the same password when exporting the token. By default, the \fBexport\fP
|
||||
operation will not encrypt the token with a password; note that it may not
|
||||
be possible to enter all possible passwords on devices with limited text
|
||||
input capabilities (such as feature phones).
|
||||
.TP
|
||||
\fB\-\-new\-pin=\fIpin\fP
|
||||
Supply a new PIN from the command line for the \fBsetpin\fP operation.
|
||||
See notes in \fBSECURITY CONSIDERATIONS\fP below.
|
||||
.TP
|
||||
\fB\-\-new\-devid=\fIdevid\fP
|
||||
Used with the \fBexport\fP or \fBissue\fP command to encrypt the new token
|
||||
with a specific device ID. This is only used for testing purposes.
|
||||
.TP
|
||||
\fB\-\-blocks\fP, \fB\-\-iphone\fP, \fB\-\-android\fP, \fB\-\-v3\fP
|
||||
Used with the \fBexport\fP command to select the output format. See examples
|
||||
in \fBBASIC USAGE\fP. By default, the \fBexport\fP command will print an
|
||||
unformatted 81-digit string to standard output.
|
||||
.TP
|
||||
\fB\-\-sdtid\fP, \fB\-\-xml\fP
|
||||
These options are synonyms. Both export a token to standard output in
|
||||
RSA's \fIsdtid\fP XML format.
|
||||
.TP
|
||||
\fB\-\-qr=\fIfile.png\fP
|
||||
Encode the token as a QR code and write it to \fIfile.png\fP. This requires
|
||||
the \fBqrencode\fP program to be installed.
|
||||
.TP
|
||||
\fB\-\-show\-qr\fP
|
||||
Encode the token as a QR code and immediately display it on the screen.
|
||||
This requires the \fBqrencode\fP program to be installed. If the
|
||||
\fBQR_VIEWER\fP environment variable is set, \fBstoken\fP will use that
|
||||
program as the preferred viewer. Otherwise it will try to execute a few
|
||||
common Linux image viewers, and give up if none of them exist.
|
||||
.TP
|
||||
\fB\-\-template=\fIfile\fP
|
||||
Used with the \fBexport\fP or \fBissue\fP commands to override fields in
|
||||
the XML output. The template file should look like any standard \fIsdtid\fP
|
||||
file, but all fields are optional and will default to reasonably sane
|
||||
values if omitted. This can be used to force the output XML to use a
|
||||
specific serial number, user name, expiration date, etc. Correct MAC
|
||||
checksums will be (re)computed on the provided values. See the
|
||||
\fIexamples\fP directory in the source distribution for more information.
|
||||
.SH "OTHER OPTIONS"
|
||||
.TP
|
||||
\fB\-\-use\-time=\fP{\fIunix_time\fP|\fB+\fIoffset\fP|\fB-\fIoffset\fP}
|
||||
Instead of generating a tokencode based on the current time of day,
|
||||
force a specific time, or adjust the current time based on a positive
|
||||
or negative offset (specified in seconds). This is only used for testing
|
||||
purposes.
|
||||
.TP
|
||||
\fB\-\-next\fP
|
||||
Generate the next tokencode instead of the current tokencode. For a 60-second
|
||||
token, this is equivalent to \fB\-\-use\-time=+60\fP.
|
||||
.TP
|
||||
\fB\-\-stdin\fP, \fB\-s\fP
|
||||
When generating a tokencode that requires \fIeither\fP a password or PIN,
|
||||
read the password or PIN as single line from standard input. This is
|
||||
intended to allow external programs to call \fIstoken\fP to generate
|
||||
single-use passwords without user intervention; see \fBNON-INTERACTIVE USE\fP
|
||||
below.
|
||||
.TP
|
||||
\fB\-\-force\fP, \fB\-f\fP
|
||||
Override token expiration date checks (for \fBtokencode\fP) or token
|
||||
overwrite checks (for \fBimport\fP).
|
||||
.TP
|
||||
\fB\-\-batch\fP, \fB\-b\fP
|
||||
Abort with an error exit code if any user input is required. Intended for
|
||||
automated operation and testing.
|
||||
.TP
|
||||
\fB\-\-file=\fIfile\fP
|
||||
Read a ctf string, an Android/iPhone URI, or an XML \fIsdtid\fP token from
|
||||
\fIfile\fP instead of the \fI.stokenrc\fP configuration. Most \fBstoken\fP
|
||||
commands accept this flag, but it is expected that the typical
|
||||
user will save his token in \fI~/.stokenrc\fP instead of supplying it by
|
||||
hand on every invocation. Typically \fB\-\-file\fP and \fB\-\-token\fP
|
||||
are only used for the \fBimport\fP command.
|
||||
.TP
|
||||
\fB\-\-token=\fItoken_string\fP
|
||||
Use a token from the command line instead of the \fI.stokenrc\fP file. See
|
||||
above notes on \fB\-\-file\fP.
|
||||
.TP
|
||||
\fB\-\-random\fP
|
||||
Generate a random token on the fly. Used for testing or demonstrations only.
|
||||
These tokens should \fBnot\fP be used for real authentication.
|
||||
.TP
|
||||
\fB\-\-help\fP, \fB\-h\fP
|
||||
Display basic usage information.
|
||||
.TP
|
||||
\fB\-\-version\fP, \fB\-v\fP
|
||||
Display version information.
|
||||
.SH "SECURITY CONSIDERATIONS"
|
||||
.PP
|
||||
Software tokens, unlike hardware tokens, are relatively easy to replicate.
|
||||
Systems that store soft token seeds should be carefully guarded to prevent
|
||||
unauthorized disclosure. The use of whole-disk encryption, such as TrueCrypt,
|
||||
is strongly recommended for laptops and other portable devices that are
|
||||
easily lost or stolen.
|
||||
.PP
|
||||
\fBstoken\fP permits users to store their PIN in \fI~/.stokenrc\fP to
|
||||
allow for automated (scriptable) generation of tokencodes, but the risks of
|
||||
this approach should be carefully weighed against the benefits.
|
||||
.PP
|
||||
Using the \fBsetpass\fP command to encrypt the seed and PIN in
|
||||
\fI~/.stokenrc\fP provides some degree of protection against unauthorized
|
||||
access, but does not necessarily cover all possible attack vectors. A
|
||||
host that is already compromised (e.g. running a keylogger) will not
|
||||
provide adequate protection for any seed(s) stored on it.
|
||||
.PP
|
||||
\fBstoken\fP encryption passwords may be up to 40 characters long.
|
||||
A longer passphrase constructed from several random words can provide
|
||||
more protection from brute-force attacks than a shorter password.
|
||||
.PP
|
||||
Entering a password or PIN on the command line is generally unsafe on
|
||||
multiuser systems, as other users may be able to view the command line
|
||||
arguments in \fBps\fP or similar utilities. The command line could
|
||||
also be cached in shell history files.
|
||||
.PP
|
||||
Encoding QR tokens may expose the seed data through \fBps\fP, and
|
||||
the \fB\-\-show\-qr\fP option writes temporary PNG files in \fB/tmp\fP.
|
||||
.PP
|
||||
\fBstoken\fP attempts to lock pages to prevent swapping out to disk, but
|
||||
does not scrub secrets from process memory.
|
||||
.SH "NON\-INTERACTIVE USE"
|
||||
.PP
|
||||
Other applications, such as VPN clients, may want to invoke \fBstoken\fP
|
||||
non-interactively to generate single-use passwords. Three usage modes are
|
||||
supported, depending on the level of security (and/or convenience) that is
|
||||
required:
|
||||
.SS No password or PIN
|
||||
.PP
|
||||
The user configures \fBstoken\fP to print a tokencode immediately upon
|
||||
invocation, with no prompts, by using \fBsetpin\fP to store the PIN in
|
||||
\fI~/.stokenrc\fP and using \fBsetpass\fP to set an empty password.
|
||||
The other application can then invoke \fBstoken \-\-batch\fP and read
|
||||
the tokencode through a pipe from standard output.
|
||||
.PP
|
||||
This provides no security for the seed, but may be useful in applications
|
||||
where (re-)authentication is frequent or unattended operation is required.
|
||||
.SS Save the PIN and set a password
|
||||
.PP
|
||||
The user configures \fBstoken\fP to encrypt the \fI~/.stokenrc\fP secrets
|
||||
with a password using \fBsetpass\fP, then saves the PIN with \fBsetpin\fP.
|
||||
The PIN and the seed will both be encrypted with the password. The other
|
||||
application will request the password from the user, then call
|
||||
\fBstoken \-\-stdin\fP, write the password to \fBstoken\fP's standard input
|
||||
through a pipe, and read back a tokencode from \fBstoken\fP's standard
|
||||
output.
|
||||
.SS No password; prompt for the PIN
|
||||
.PP
|
||||
Similar to above, but set an empty password using \fBsetpass\fP, do not
|
||||
save the PIN in \fI~/.stokenrc\fP, and pass the PIN to \fBstoken \-\-stdin\fP
|
||||
via standard input.
|
||||
.SH "BUGS/TODO"
|
||||
.PP
|
||||
\fIsdtid\fP support is still new and may choke on unexpected input.
|
||||
As a short\-term workaround you can try commenting out the
|
||||
sanity checks in \fBsdtid_decrypt()\fP to see if the problem goes away.
|
||||
.PP
|
||||
Features under development include:
|
||||
hardware token seeds (and the \fBstoken split\fP command needed to work with
|
||||
them), and support for non\-Linux hosts.
|
||||
.PP
|
||||
Patches are always welcome.
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
\fBstoken\-gui\fP(1).
|
||||
.SH FILES
|
||||
.TP
|
||||
~/.stokenrc
|
||||
Default configuration file.
|
||||
.SH "AUTHOR"
|
||||
Kevin Cernekee <cernekee@gmail.com>
|
|
@ -0,0 +1,11 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: stoken
|
||||
Description: Software token
|
||||
Version: @VERSION@
|
||||
Requires.private: libxml-2.0, @DEPS_PC@
|
||||
Libs: -L${libdir} -lstoken @EXTRA_PC_LIBS@
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,2 @@
|
|||
*.log
|
||||
*.trs
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0"?>
|
||||
<TKNBatch>
|
||||
<TKNHeader>
|
||||
<Version>0</Version>
|
||||
<Origin>N/A</Origin>
|
||||
<Dest>N/A</Dest>
|
||||
<Name>N/A</Name>
|
||||
<FirstToken>N/A</FirstToken>
|
||||
<LastToken>N/A</LastToken>
|
||||
<NumTokens>0</NumTokens>
|
||||
<Secret>DhSQ8e/0CDoq3TdNPDjvMw==</Secret>
|
||||
<DefBirth>2000/01/01</DefBirth>
|
||||
<DefDeath>2038/01/18</DefDeath>
|
||||
<DefDigits>8</DefDigits>
|
||||
<DefInterval>60</DefInterval>
|
||||
<DefAlg>1</DefAlg>
|
||||
<DefMode>0</DefMode>
|
||||
<DefPrecision>2400</DefPrecision>
|
||||
<DefSmallWin>630</DefSmallWin>
|
||||
<DefMediumWin>4320</DefMediumWin>
|
||||
<DefLargeWin>4320</DefLargeWin>
|
||||
<DefAddPIN>1</DefAddPIN>
|
||||
<DefLocalPIN>1</DefLocalPIN>
|
||||
<DefCopyProtection>1</DefCopyProtection>
|
||||
<DefPinType>0</DefPinType>
|
||||
<DefKeypad>1</DefKeypad>
|
||||
<DefProtLevel>0</DefProtLevel>
|
||||
<DefRevision>0</DefRevision>
|
||||
<DefTimeDerivedSeeds>1</DefTimeDerivedSeeds>
|
||||
<DefAppDerivedSeeds>0</DefAppDerivedSeeds>
|
||||
<DefFormFactor>20000001</DefFormFactor>
|
||||
<HeaderMAC>dY+8gSNYrxbywmBd2ou18Q==</HeaderMAC>
|
||||
</TKNHeader>
|
||||
<TKN>
|
||||
<SN>584917508172</SN>
|
||||
<Seed>=EAn5SLIT+nMMYUC3JH+eDw==</Seed>
|
||||
<UserFirstName> </UserFirstName>
|
||||
<UserLastName> </UserLastName>
|
||||
<UserLogin> </UserLogin>
|
||||
<TokenAttributes>
|
||||
<DeviceSerialNumber>a01c4380-fc01-4df0-b113-7fb98ec74694</DeviceSerialNumber>
|
||||
<Nickname> </Nickname>
|
||||
</TokenAttributes>
|
||||
<TokenMAC>KDXMn8UWRprjjjmdO055oA==</TokenMAC>
|
||||
</TKN>
|
||||
<TKNTrailer>
|
||||
<BatchSignature>Mnq7atVBljepJU3ybPaF4iB+7i8tpwAPI5Fh6ahYS5UuuxnAsDEN4IFd93FfAoyAGG2Wuq9HuZ7uii87vRbF3GbvnzwHzF7XI3W9uC5TIA67YUyCuErXgHCcA+1w9gE4t25VgQ6R2hsREjjTA4RgoogQqFHDus/PGdWiMdVMQRg=</BatchSignature>
|
||||
<BatchCertificate>MIICeTCCAWGgAwIBAgIQM0NFNTU4NTMzMDlGODEzMDANBgkqhkiG9w0BAQQFADBBMT8wPQYDVQQDEzZTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMsIEluYy4gUHJpbWFyeSBDQSBSb290IDEwHhcNMDIwNTE3MTkyMTU1WhcNMjIwNTEyMTkyMTU1WjA0MTIwMAYDVQQDEylTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMgQUNFL1NlcnZlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1np1DIf3HOHAK2ahcRzZCJsqIC1QMEqtsdanKSEn5CGtLCdLv9LbLUYo6cQxKSJtwvigpeDgBAb/UYcUNXy/7dY7rA5WpYlsaA9h5C9qzPMBHxVGSIe5k61uUbAwdFhCMfLh776wR//VZ7cuypo5d3cCbvgHGwqw4ZuECbKvONMCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAq8MMJs1SczwpfcZqn9loM+2RhFmN1IZiXyevz1VvGD9GUrlLalm/Et989zR/dVhciGXmAAxYnV/MoZmshjXozmJgjRmfqqHLS46UJ9nLZ2BuEVcrHnn6f9meIjeMWm+Dvh+8Vi9KJOLozYbDoaUMm+5F7ywKsUuBPRSJ1ykGJG6dOCBZlJGmM3kbZ54lRAK2TYcu2JM21i7BKdeE9xItyabJzEk3QCsX0erY7h3V//okIfKWLh8LieoWbV4+VtrQEoiUwyqdYswwgMOyRiKuGTkk3DhHdoqhG8SqHSxkPto42hEnpOx9j2rqcsOWosvNyfm9nwkqJfhuJClLwOzw5Q==</BatchCertificate>
|
||||
</TKNTrailer>
|
||||
</TKNBatch>
|
|
@ -0,0 +1 @@
|
|||
$STOKEN export --android $tok0
|
|
@ -0,0 +1 @@
|
|||
http://127.0.0.1/securid/ctf?ctfData=258491750817210752367175001073261277346642631755724762324173166222072476671635706
|
|
@ -0,0 +1 @@
|
|||
$STOKEN export --iphone $tok0 --new-password asdf
|
|
@ -0,0 +1 @@
|
|||
com.rsa.securid.iphone://ctf?ctfData=258491750817271376337025556032745736615071405660444767006173166222072476671610011
|
|
@ -0,0 +1,2 @@
|
|||
$STOKEN export --v3 $tok0
|
||||
$STOKEN export --blocks --token $out
|
|
@ -0,0 +1 @@
|
|||
25849-17508-17210-75236-71750-01073-26127-73466-42631-75572-47623-24172-16622-20724-72716-77463-6
|
|
@ -0,0 +1 @@
|
|||
$STOKEN export $tok0 --sdtid --template $TESTDIR/fixed-secret.xml --new-devid 'a01c4380-fc01-4df0-b113-7fb98ec74694' --new-password 'Correct_horse!battery&staple'
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0"?>
|
||||
<TKNBatch>
|
||||
<TKNHeader>
|
||||
<Version>0</Version>
|
||||
<Origin>N/A</Origin>
|
||||
<Dest>N/A</Dest>
|
||||
<Name>N/A</Name>
|
||||
<FirstToken>N/A</FirstToken>
|
||||
<LastToken>N/A</LastToken>
|
||||
<NumTokens>0</NumTokens>
|
||||
<Secret>WTFNzycMvOXcvS7UKDpKWA==</Secret>
|
||||
<DefBirth>2000/01/01</DefBirth>
|
||||
<DefDeath>2038/01/18</DefDeath>
|
||||
<DefDigits>8</DefDigits>
|
||||
<DefInterval>60</DefInterval>
|
||||
<DefAlg>1</DefAlg>
|
||||
<DefMode>0</DefMode>
|
||||
<DefPrecision>2400</DefPrecision>
|
||||
<DefSmallWin>630</DefSmallWin>
|
||||
<DefMediumWin>4320</DefMediumWin>
|
||||
<DefLargeWin>4320</DefLargeWin>
|
||||
<DefAddPIN>1</DefAddPIN>
|
||||
<DefLocalPIN>1</DefLocalPIN>
|
||||
<DefCopyProtection>1</DefCopyProtection>
|
||||
<DefPinType>0</DefPinType>
|
||||
<DefKeypad>1</DefKeypad>
|
||||
<DefProtLevel>0</DefProtLevel>
|
||||
<DefRevision>0</DefRevision>
|
||||
<DefTimeDerivedSeeds>1</DefTimeDerivedSeeds>
|
||||
<DefAppDerivedSeeds>0</DefAppDerivedSeeds>
|
||||
<DefFormFactor>20000001</DefFormFactor>
|
||||
<HeaderMAC>JrxjfjsTffwm7ztFeqD++w==</HeaderMAC>
|
||||
</TKNHeader>
|
||||
<TKN>
|
||||
<SN>584917508172</SN>
|
||||
<Seed>=y5PhhfjspvRPB/ZbrMZKfg==</Seed>
|
||||
<UserFirstName> </UserFirstName>
|
||||
<UserLastName> </UserLastName>
|
||||
<UserLogin> </UserLogin>
|
||||
<TokenAttributes>
|
||||
<DeviceSerialNumber>a01c4380-fc01-4df0-b113-7fb98ec74694</DeviceSerialNumber>
|
||||
<Nickname> </Nickname>
|
||||
</TokenAttributes>
|
||||
<TokenMAC>3RVitQbpQDnjBQQjdqVbSw==</TokenMAC>
|
||||
</TKN>
|
||||
<TKNTrailer>
|
||||
<BatchSignature>Vr3pVXbhsCuyUuGFYGaF+UwqmfdfkhMZdcDR5+s3y5O8vH9jth7AtQj2idPr2L3GIGFAShGx9OPYF7044nS7pIeMMTgtAttnQvNaBK/FFK3D+qDdsv9asKOG546LlbXBP/DIkOr0PbAxBhilY8CuUiMxUbBqkqP8dzMCxUOV/a8=</BatchSignature>
|
||||
<BatchCertificate>MIICeTCCAWGgAwIBAgIQM0NFNTU4NTMzMDlGODEzMDANBgkqhkiG9w0BAQQFADBBMT8wPQYDVQQDEzZTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMsIEluYy4gUHJpbWFyeSBDQSBSb290IDEwHhcNMDIwNTE3MTkyMTU1WhcNMjIwNTEyMTkyMTU1WjA0MTIwMAYDVQQDEylTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMgQUNFL1NlcnZlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1np1DIf3HOHAK2ahcRzZCJsqIC1QMEqtsdanKSEn5CGtLCdLv9LbLUYo6cQxKSJtwvigpeDgBAb/UYcUNXy/7dY7rA5WpYlsaA9h5C9qzPMBHxVGSIe5k61uUbAwdFhCMfLh776wR//VZ7cuypo5d3cCbvgHGwqw4ZuECbKvONMCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAq8MMJs1SczwpfcZqn9loM+2RhFmN1IZiXyevz1VvGD9GUrlLalm/Et989zR/dVhciGXmAAxYnV/MoZmshjXozmJgjRmfqqHLS46UJ9nLZ2BuEVcrHnn6f9meIjeMWm+Dvh+8Vi9KJOLozYbDoaUMm+5F7ywKsUuBPRSJ1ykGJG6dOCBZlJGmM3kbZ54lRAK2TYcu2JM21i7BKdeE9xItyabJzEk3QCsX0erY7h3V//okIfKWLh8LieoWbV4+VtrQEoiUwyqdYswwgMOyRiKuGTkk3DhHdoqhG8SqHSxkPto42hEnpOx9j2rqcsOWosvNyfm9nwkqJfhuJClLwOzw5Q==</BatchCertificate>
|
||||
</TKNTrailer>
|
||||
</TKNBatch>
|
|
@ -0,0 +1,2 @@
|
|||
$STOKEN export --v3 --file $TESTDIR/pinmode-2.sdtid
|
||||
$STOKEN export --token $out --sdtid --template $TESTDIR/fixed-secret.xml
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0"?>
|
||||
<TKNBatch>
|
||||
<TKNHeader>
|
||||
<Version>0</Version>
|
||||
<Origin>N/A</Origin>
|
||||
<Dest>N/A</Dest>
|
||||
<Name>N/A</Name>
|
||||
<FirstToken>N/A</FirstToken>
|
||||
<LastToken>N/A</LastToken>
|
||||
<NumTokens>0</NumTokens>
|
||||
<Secret>WTFNzycMvOXcvS7UKDpKWA==</Secret>
|
||||
<DefBirth>2000/01/01</DefBirth>
|
||||
<DefDeath>2038/01/18</DefDeath>
|
||||
<DefDigits>8</DefDigits>
|
||||
<DefInterval>60</DefInterval>
|
||||
<DefAlg>1</DefAlg>
|
||||
<DefMode>0</DefMode>
|
||||
<DefPrecision>2400</DefPrecision>
|
||||
<DefSmallWin>630</DefSmallWin>
|
||||
<DefMediumWin>4320</DefMediumWin>
|
||||
<DefLargeWin>4320</DefLargeWin>
|
||||
<DefAddPIN>1</DefAddPIN>
|
||||
<DefLocalPIN>0</DefLocalPIN>
|
||||
<DefCopyProtection>1</DefCopyProtection>
|
||||
<DefPinType>0</DefPinType>
|
||||
<DefKeypad>1</DefKeypad>
|
||||
<DefProtLevel>0</DefProtLevel>
|
||||
<DefRevision>0</DefRevision>
|
||||
<DefTimeDerivedSeeds>1</DefTimeDerivedSeeds>
|
||||
<DefAppDerivedSeeds>0</DefAppDerivedSeeds>
|
||||
<DefFormFactor>20000001</DefFormFactor>
|
||||
<HeaderMAC>zOwik/DkqmPnv7ZlHejHNw==</HeaderMAC>
|
||||
</TKNHeader>
|
||||
<TKN>
|
||||
<SN>127456102283</SN>
|
||||
<Seed>=f9XQ2HTtHfdLO7DUQ5+V4Q==</Seed>
|
||||
<UserFirstName> </UserFirstName>
|
||||
<UserLastName> </UserLastName>
|
||||
<UserLogin> </UserLogin>
|
||||
<TokenAttributes>
|
||||
<DeviceSerialNumber> </DeviceSerialNumber>
|
||||
<Nickname> </Nickname>
|
||||
</TokenAttributes>
|
||||
<TokenMAC>x4rl0smdX32WW9hYiWkgsg==</TokenMAC>
|
||||
</TKN>
|
||||
<TKNTrailer>
|
||||
<BatchSignature>eiePYA7QXEsqy8IhKzMs0/7QHJUPBzvb1YJorh4wbVirsq+FyJy60Oa8N1smABcj6LBottggtshY75E59VRa5OGlxU1DiS2O+UpVeaqLvBpfEl2DR1ZkLZCsKmCY++zrnQrOS8xcmAEQcgrkX4rQI0C91mbQb3NDf3COtT12OmM=</BatchSignature>
|
||||
<BatchCertificate>MIICeTCCAWGgAwIBAgIQM0NFNTU4NTMzMDlGODEzMDANBgkqhkiG9w0BAQQFADBBMT8wPQYDVQQDEzZTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMsIEluYy4gUHJpbWFyeSBDQSBSb290IDEwHhcNMDIwNTE3MTkyMTU1WhcNMjIwNTEyMTkyMTU1WjA0MTIwMAYDVQQDEylTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMgQUNFL1NlcnZlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1np1DIf3HOHAK2ahcRzZCJsqIC1QMEqtsdanKSEn5CGtLCdLv9LbLUYo6cQxKSJtwvigpeDgBAb/UYcUNXy/7dY7rA5WpYlsaA9h5C9qzPMBHxVGSIe5k61uUbAwdFhCMfLh776wR//VZ7cuypo5d3cCbvgHGwqw4ZuECbKvONMCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAq8MMJs1SczwpfcZqn9loM+2RhFmN1IZiXyevz1VvGD9GUrlLalm/Et989zR/dVhciGXmAAxYnV/MoZmshjXozmJgjRmfqqHLS46UJ9nLZ2BuEVcrHnn6f9meIjeMWm+Dvh+8Vi9KJOLozYbDoaUMm+5F7ywKsUuBPRSJ1ykGJG6dOCBZlJGmM3kbZ54lRAK2TYcu2JM21i7BKdeE9xItyabJzEk3QCsX0erY7h3V//okIfKWLh8LieoWbV4+VtrQEoiUwyqdYswwgMOyRiKuGTkk3DhHdoqhG8SqHSxkPto42hEnpOx9j2rqcsOWosvNyfm9nwkqJfhuJClLwOzw5Q==</BatchCertificate>
|
||||
</TKNTrailer>
|
||||
</TKNBatch>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<TKNBatch>
|
||||
<TKNHeader>
|
||||
<Secret>WTFNzycMvOXcvS7UKDpKWA==</Secret>
|
||||
</TKNHeader>
|
||||
</TKNBatch>
|
|
@ -0,0 +1 @@
|
|||
$STOKEN export --android --file $TESTDIR/mac-align.sdtid
|
|
@ -0,0 +1 @@
|
|||
http://127.0.0.1/securid/ctf?ctfData=299792244709622667530306243203205436512412555314055336764172166222314456671666125
|
|
@ -0,0 +1,104 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
|
||||
This tests the "bug compatibility" code in recursive_hash(), which provides
|
||||
special handling for hashing short strings. Here is an example of a BAD
|
||||
hash:
|
||||
|
||||
00000000 54 4b 4e 2e 53 4e 20 39 39 37 39 32 32 34 34 37 |TKN.SN 997922447|
|
||||
00000010 30 39 36 0a 54 4b 4e 2e 53 65 65 64 20 3d 79 4f |096.TKN.Seed =yO|
|
||||
00000020 45 4d 6e 6a 59 2f 62 4f 61 73 52 61 5a 6b 39 4c |EMnjY/bOasRaZk9L|
|
||||
00000030 74 33 6b 51 3d 3d 0a 00 00 00 00 54 4b 4e 2e 55 |t3kQ==.....TKN.U|
|
||||
00000040 73 65 72 46 69 72 73 74 4e 61 6d 65 20 41 6c 69 |serFirstName Ali|
|
||||
00000050 67 6e 6d 65 6e 74 0a 00 00 00 00 00 00 00 00 00 |gnment..........|
|
||||
00000060 00 00 54 4b 4e 2e 55 73 65 72 4c 61 73 74 4e 61 |..TKN.UserLastNa|
|
||||
00000070 6d 65 20 54 65 73 74 20 43 73 0a 00 00 54 4b 4e |me Test Cs...TKN|
|
||||
00000080 2e 55 73 65 72 4c 6f 67 69 6e 20 61 6c 69 67 6e |.UserLogin align|
|
||||
00000090 74 65 73 74 0a 00 00 00 00 00 00 00 00 00 00 00 |test............|
|
||||
000000a0 00 00 54 4b 4e 2e 41 64 64 50 49 4e 20 31 0a 00 |..TKN.AddPIN 1..|
|
||||
000000b0 00 54 4b 4e 2e 4c 6f 63 61 6c 50 49 4e 20 31 0a |.TKN.LocalPIN 1.|
|
||||
000000c0 00 54 4b 4e 2e 54 6f 6b 65 6e 41 74 74 72 69 62 |.TKN.TokenAttrib|
|
||||
000000d0 75 74 65 73 2e 44 65 76 69 63 65 53 65 72 69 61 |utes.DeviceSeria|
|
||||
000000e0 6c 4e 75 6d 62 65 72 20 20 0a 00 54 4b 4e 2e 54 |lNumber ..TKN.T|
|
||||
000000f0 6f 6b 65 6e 41 74 74 72 69 62 75 74 65 73 2e 4e |okenAttributes.N|
|
||||
00000100 69 63 6b 6e 61 6d 65 20 20 0a 00 00 00 00 00 00 |ickname .......|
|
||||
00000110 00 00 00 00 00 |.....|
|
||||
|
||||
TKN.AddPin starts and ends within a single AES block, so it should be
|
||||
aligned to the start of the block (offset 0xa0). The correct version looks
|
||||
like this:
|
||||
|
||||
00000000 54 4b 4e 2e 53 4e 20 39 39 37 39 32 32 34 34 37 |TKN.SN 997922447|
|
||||
00000010 30 39 36 0a 54 4b 4e 2e 53 65 65 64 20 3d 79 4f |096.TKN.Seed =yO|
|
||||
00000020 45 4d 6e 6a 59 2f 62 4f 61 73 52 61 5a 6b 39 4c |EMnjY/bOasRaZk9L|
|
||||
00000030 74 33 6b 51 3d 3d 0a 00 00 00 00 54 4b 4e 2e 55 |t3kQ==.....TKN.U|
|
||||
00000040 73 65 72 46 69 72 73 74 4e 61 6d 65 20 41 6c 69 |serFirstName Ali|
|
||||
00000050 67 6e 6d 65 6e 74 0a 00 00 00 00 00 00 00 00 00 |gnment..........|
|
||||
00000060 00 00 54 4b 4e 2e 55 73 65 72 4c 61 73 74 4e 61 |..TKN.UserLastNa|
|
||||
00000070 6d 65 20 54 65 73 74 20 43 73 0a 00 00 54 4b 4e |me Test Cs...TKN|
|
||||
00000080 2e 55 73 65 72 4c 6f 67 69 6e 20 61 6c 69 67 6e |.UserLogin align|
|
||||
00000090 74 65 73 74 0a 00 00 00 00 00 00 00 00 00 00 00 |test............|
|
||||
000000a0 54 4b 4e 2e 41 64 64 50 49 4e 20 31 0a 00 00 54 |TKN.AddPIN 1...T|
|
||||
000000b0 4b 4e 2e 4c 6f 63 61 6c 50 49 4e 20 31 0a 00 00 |KN.LocalPIN 1...|
|
||||
000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 54 4b 4e |.............TKN|
|
||||
000000d0 2e 54 6f 6b 65 6e 41 74 74 72 69 62 75 74 65 73 |.TokenAttributes|
|
||||
000000e0 2e 44 65 76 69 63 65 53 65 72 69 61 6c 4e 75 6d |.DeviceSerialNum|
|
||||
000000f0 62 65 72 20 20 0a 00 00 00 00 00 00 00 00 00 00 |ber ...........|
|
||||
00000100 00 00 00 54 4b 4e 2e 54 6f 6b 65 6e 41 74 74 72 |...TKN.TokenAttr|
|
||||
00000110 69 62 75 74 65 73 2e 4e 69 63 6b 6e 61 6d 65 20 |ibutes.Nickname |
|
||||
00000120 20 0a 00 00 00 | ....|
|
||||
|
||||
-->
|
||||
|
||||
<TKNBatch>
|
||||
<TKNHeader>
|
||||
<Version>0</Version>
|
||||
<Origin>N/A</Origin>
|
||||
<Dest>N/A</Dest>
|
||||
<Name>N/A</Name>
|
||||
<FirstToken>N/A</FirstToken>
|
||||
<LastToken>N/A</LastToken>
|
||||
<NumTokens>0</NumTokens>
|
||||
<Secret>WTFNzycMvOXcvS7UKDpKWA==</Secret>
|
||||
<DefBirth>2000/01/01</DefBirth>
|
||||
<DefDeath>2038/01/18</DefDeath>
|
||||
<DefDigits>8</DefDigits>
|
||||
<DefInterval>60</DefInterval>
|
||||
<DefAlg>1</DefAlg>
|
||||
<DefMode>0</DefMode>
|
||||
<DefPrecision>2400</DefPrecision>
|
||||
<DefSmallWin>630</DefSmallWin>
|
||||
<DefMediumWin>4320</DefMediumWin>
|
||||
<DefLargeWin>4320</DefLargeWin>
|
||||
<DefAddPIN>1</DefAddPIN>
|
||||
<DefLocalPIN>0</DefLocalPIN>
|
||||
<DefCopyProtection>1</DefCopyProtection>
|
||||
<DefPinType>0</DefPinType>
|
||||
<DefKeypad>1</DefKeypad>
|
||||
<DefProtLevel>0</DefProtLevel>
|
||||
<DefRevision>0</DefRevision>
|
||||
<DefTimeDerivedSeeds>1</DefTimeDerivedSeeds>
|
||||
<DefAppDerivedSeeds>0</DefAppDerivedSeeds>
|
||||
<DefFormFactor>20000001</DefFormFactor>
|
||||
<HeaderMAC>zOwik/DkqmPnv7ZlHejHNw==</HeaderMAC>
|
||||
</TKNHeader>
|
||||
<TKN>
|
||||
<SN>997922447096</SN>
|
||||
<Seed>=yOEMnjY/bOasRaZk9Lt3kQ==</Seed>
|
||||
<UserFirstName>Alignment</UserFirstName>
|
||||
<UserLastName>Test Cs</UserLastName>
|
||||
<UserLogin>aligntest</UserLogin>
|
||||
<AddPIN>1</AddPIN>
|
||||
<LocalPIN>0</LocalPIN>
|
||||
<TokenAttributes>
|
||||
<DeviceSerialNumber> </DeviceSerialNumber>
|
||||
<Nickname> </Nickname>
|
||||
</TokenAttributes>
|
||||
<TokenMAC>7rhsO4+hQZ1vKSDnule/4g==</TokenMAC>
|
||||
</TKN>
|
||||
<TKNTrailer>
|
||||
<BatchSignature>qauF4qGbpAKrnKgzS7JoCZGQ1Srpk0digJ/usaf2pdfEISPhEXdqsBaDQ8c+gBb36QGL8LEOmNpbaQBZeTMnKz6fwVfHTgfYRU0uXDPLKQdwsMT7B3KCAMopEhMyM+tkkkeaxhQPl1ZuxBCt5CN9tsdpml2ywAC5QAGBN2ujUT4=</BatchSignature>
|
||||
<BatchCertificate>MIICeTCCAWGgAwIBAgIQM0NFNTU4NTMzMDlGODEzMDANBgkqhkiG9w0BAQQFADBBMT8wPQYDVQQDEzZTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMsIEluYy4gUHJpbWFyeSBDQSBSb290IDEwHhcNMDIwNTE3MTkyMTU1WhcNMjIwNTEyMTkyMTU1WjA0MTIwMAYDVQQDEylTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMgQUNFL1NlcnZlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1np1DIf3HOHAK2ahcRzZCJsqIC1QMEqtsdanKSEn5CGtLCdLv9LbLUYo6cQxKSJtwvigpeDgBAb/UYcUNXy/7dY7rA5WpYlsaA9h5C9qzPMBHxVGSIe5k61uUbAwdFhCMfLh776wR//VZ7cuypo5d3cCbvgHGwqw4ZuECbKvONMCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAq8MMJs1SczwpfcZqn9loM+2RhFmN1IZiXyevz1VvGD9GUrlLalm/Et989zR/dVhciGXmAAxYnV/MoZmshjXozmJgjRmfqqHLS46UJ9nLZ2BuEVcrHnn6f9meIjeMWm+Dvh+8Vi9KJOLozYbDoaUMm+5F7ywKsUuBPRSJ1ykGJG6dOCBZlJGmM3kbZ54lRAK2TYcu2JM21i7BKdeE9xItyabJzEk3QCsX0erY7h3V//okIfKWLh8LieoWbV4+VtrQEoiUwyqdYswwgMOyRiKuGTkk3DhHdoqhG8SqHSxkPto42hEnpOx9j2rqcsOWosvNyfm9nwkqJfhuJClLwOzw5Q==</BatchCertificate>
|
||||
</TKNTrailer>
|
||||
</TKNBatch>
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0"?>
|
||||
<TKNBatch>
|
||||
<TKNHeader>
|
||||
<Version>0</Version>
|
||||
<Origin>N/A</Origin>
|
||||
<Dest>N/A</Dest>
|
||||
<Name>N/A</Name>
|
||||
<FirstToken>N/A</FirstToken>
|
||||
<LastToken>N/A</LastToken>
|
||||
<NumTokens>0</NumTokens>
|
||||
<Secret>WTFNzycMvOXcvS7UKDpKWA==</Secret>
|
||||
<DefBirth>2000/01/01</DefBirth>
|
||||
<DefDeath>2038/01/18</DefDeath>
|
||||
<DefDigits>8</DefDigits>
|
||||
<DefInterval>60</DefInterval>
|
||||
<DefAlg>1</DefAlg>
|
||||
<DefMode>0</DefMode>
|
||||
<DefPrecision>2400</DefPrecision>
|
||||
<DefSmallWin>630</DefSmallWin>
|
||||
<DefMediumWin>4320</DefMediumWin>
|
||||
<DefLargeWin>4320</DefLargeWin>
|
||||
<DefAddPIN>1</DefAddPIN>
|
||||
<DefLocalPIN>0</DefLocalPIN>
|
||||
<DefCopyProtection>1</DefCopyProtection>
|
||||
<DefPinType>0</DefPinType>
|
||||
<DefKeypad>1</DefKeypad>
|
||||
<DefProtLevel>0</DefProtLevel>
|
||||
<DefRevision>0</DefRevision>
|
||||
<DefTimeDerivedSeeds>1</DefTimeDerivedSeeds>
|
||||
<DefAppDerivedSeeds>0</DefAppDerivedSeeds>
|
||||
<DefFormFactor>20000001</DefFormFactor>
|
||||
<HeaderMAC>zOwik/DkqmPnv7ZlHejHNw==</HeaderMAC>
|
||||
</TKNHeader>
|
||||
<TKN>
|
||||
<SN>127456102283</SN>
|
||||
<Seed>=f9XQ2HTtHfdLO7DUQ5+V4Q==</Seed>
|
||||
<UserFirstName> </UserFirstName>
|
||||
<UserLastName> </UserLastName>
|
||||
<UserLogin> </UserLogin>
|
||||
<TokenAttributes>
|
||||
<DeviceSerialNumber> </DeviceSerialNumber>
|
||||
<Nickname> </Nickname>
|
||||
</TokenAttributes>
|
||||
<TokenMAC>x4rl0smdX32WW9hYiWkgsg==</TokenMAC>
|
||||
</TKN>
|
||||
<TKNTrailer>
|
||||
<BatchSignature>eiePYA7QXEsqy8IhKzMs0/7QHJUPBzvb1YJorh4wbVirsq+FyJy60Oa8N1smABcj6LBottggtshY75E59VRa5OGlxU1DiS2O+UpVeaqLvBpfEl2DR1ZkLZCsKmCY++zrnQrOS8xcmAEQcgrkX4rQI0C91mbQb3NDf3COtT12OmM=</BatchSignature>
|
||||
<BatchCertificate>MIICeTCCAWGgAwIBAgIQM0NFNTU4NTMzMDlGODEzMDANBgkqhkiG9w0BAQQFADBBMT8wPQYDVQQDEzZTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMsIEluYy4gUHJpbWFyeSBDQSBSb290IDEwHhcNMDIwNTE3MTkyMTU1WhcNMjIwNTEyMTkyMTU1WjA0MTIwMAYDVQQDEylTZWN1cml0eSBEeW5hbWljcyBUZWNobm9sb2dpZXMgQUNFL1NlcnZlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1np1DIf3HOHAK2ahcRzZCJsqIC1QMEqtsdanKSEn5CGtLCdLv9LbLUYo6cQxKSJtwvigpeDgBAb/UYcUNXy/7dY7rA5WpYlsaA9h5C9qzPMBHxVGSIe5k61uUbAwdFhCMfLh776wR//VZ7cuypo5d3cCbvgHGwqw4ZuECbKvONMCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAq8MMJs1SczwpfcZqn9loM+2RhFmN1IZiXyevz1VvGD9GUrlLalm/Et989zR/dVhciGXmAAxYnV/MoZmshjXozmJgjRmfqqHLS46UJ9nLZ2BuEVcrHnn6f9meIjeMWm+Dvh+8Vi9KJOLozYbDoaUMm+5F7ywKsUuBPRSJ1ykGJG6dOCBZlJGmM3kbZ54lRAK2TYcu2JM21i7BKdeE9xItyabJzEk3QCsX0erY7h3V//okIfKWLh8LieoWbV4+VtrQEoiUwyqdYswwgMOyRiKuGTkk3DhHdoqhG8SqHSxkPto42hEnpOx9j2rqcsOWosvNyfm9nwkqJfhuJClLwOzw5Q==</BatchCertificate>
|
||||
</TKNTrailer>
|
||||
</TKNBatch>
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Each .pipe file contains a "pipeline" of commands. Compare the output
|
||||
# of the FINAL command to <foo>.ref
|
||||
#
|
||||
# Variables available to the .pipe test cases:
|
||||
# $STOKEN - path to stoken executable
|
||||
# $out - the last command's output
|
||||
# $TESTDIR - path to test directory
|
||||
# $tok0 - sample v2 ctf token (no devid/pass)
|
||||
#
|
||||
# To regenerate all output files, use "make check TESTGEN=1"
|
||||
|
||||
set -ex
|
||||
|
||||
base="$1"
|
||||
if [[ "$base" != *.pipe ]]; then
|
||||
echo "Invalid test file: $base"
|
||||
exit 1
|
||||
fi
|
||||
base="${base%.pipe}"
|
||||
|
||||
TESTDIR="${TESTDIR:-.}"
|
||||
STOKEN="${STOKEN:-../stoken}"
|
||||
LIBTOOL="${LIBTOOL:-../libtool}"
|
||||
if ! test -z "${VALGRIND}"; then
|
||||
STOKEN="${LIBTOOL} --mode=execute ${VALGRIND} ${STOKEN}"
|
||||
fi
|
||||
|
||||
tok0="--token=258491750817210752367175001073261277346642631755724762324173166222072472716737543"
|
||||
|
||||
out=""
|
||||
while read x; do
|
||||
out=`eval $x`
|
||||
done < ${base}.pipe
|
||||
|
||||
if [ "$TESTGEN" = "1" ]; then
|
||||
echo "$out" > ${base}.ref
|
||||
else
|
||||
ref=`cat ${base}.ref`
|
||||
[ "$out" != "$ref" ] && exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
|
@ -0,0 +1 @@
|
|||
$STOKEN tokencode --file $TESTDIR/devid-passwd.sdtid --use-time 1410710132 --pin 1234 --password 'Correct_horse!battery&staple'
|
|
@ -0,0 +1 @@
|
|||
27957523
|
|
@ -0,0 +1 @@
|
|||
$STOKEN tokencode --token 'http://127.0.0.1/securid/ctf?ctfData=258491750817210752367175001073261277346642631755724762324173166222072472716737543' --use-time 1409757465 --pin 9999
|
|
@ -0,0 +1 @@
|
|||
65365425
|
|
@ -0,0 +1 @@
|
|||
$STOKEN tokencode --token 'http://127.0.0.1/securid/ctf?ctfData=AwEBWoDfCnTYFHKM8RvGCXEbSiReGdGgA88EDrIP6EhAe8tzPkIGiAaXXtInt6UHsgM1NFmwuTVjOlJXIpNXxmj7Iud0hfL2kLmIdPgRiS6jP%2FO8q9Fcpwo%2F8tLukZRoIU7gdFjpSl3teO%2FMWlr9rJBZtkTW4q0mAehJ1tl4l0vGjcDycwmIgyzeods7F43ljVETNZjlHkDTudosNSvmS%2Bl643vFrM6NGT%2BHLrlCX0igfo5i4yaUKwDDS4AiAEq%2Bpp0dv8ZzkpZIEJikRzeWaxpfml%2BmsakJ%2BYAVFcfBoR2%2BLzr1%2Flp7mX%2BwMw4TFDZ4hS88BMY3P7uV9%2BGNz08Euaru779p4XDde0JxrPGPuGjWxUBt%2BN5aUjJkcXvAtswhfirK' --use-time 1410710132 --pin 1234 --password 'Correct_horse!battery&staple' --devid 'a01c4380-fc01-4df0-b113-7fb98ec74694'
|
|
@ -0,0 +1 @@
|
|||
27957523
|
Loading…
Reference in New Issue