07070100000000000081A400000000000000000000000167D9F0D900000028000000000000000000000000000000000000002000000000libsecret-0.21.7/.dir-locals.el((c-mode . ((c-file-style . "linux")))) 07070100000001000081A400000000000000000000000167D9F0D900000610000000000000000000000000000000000000001C00000000libsecret-0.21.7/.gitignore*~ *.bak *.deps *.gcov *.gcno *.gcda *.gir *.gmo *.la *.lo *.o *.patch *.pyc *.pc *.tar.gz *.typelib *.vapi .deps .cproject .libs .project .pydevproject aclocal.m4 autom4te.cache compile configure config.* depcomp install-sh INSTALL libtool ltmain.sh Makefile Makefile.in Makefile.in.in missing stamp* *.stamp .settings .project .cproject /build/coverage* /build/m4/* !/build/m4/vapigen.m4 /build/valgrind-suppressions /build/test-driver /build/litter /docs/man/secret-tool.1 /docs/reference/libsecret/version.xml /docs/reference/libsecret/version-major.xml /docs/reference/libsecret/libsecret-decl-list.txt /docs/reference/libsecret/libsecret-decl.txt /docs/reference/libsecret/libsecret-scan.c /docs/reference/libsecret/html /docs/reference/libsecret/libsecret-undeclared.txt /docs/reference/libsecret/libsecret-undocumented.txt /docs/reference/libsecret/libsecret-unused.txt /docs/reference/libsecret/libsecret.args /docs/reference/libsecret/libsecret.hierarchy /docs/reference/libsecret/libsecret.interfaces /docs/reference/libsecret/libsecret.prerequisites /docs/reference/libsecret/libsecret.signals /docs/reference/libsecret/tmpl /docs/reference/libsecret/xml /po/POTFILES /po/libsecret.pot /egg/tests/test-* !/egg/tests/test-*.c /libsecret/*-dbus-generated.[ch] /libsecret/secret-enum-types.[ch] /libsecret/secret-version.h /libsecret/tests/test-* /libsecret/tests/*.metadata !/libsecret/tests/test-*.c !/libsecret/tests/test-*.js !/libsecret/tests/test-*.py !/libsecret/tests/test-*.vala /libsecret/tests/test-vala-*.c /tool/secret-tool 07070100000002000081A400000000000000000000000167D9F0D900001C67000000000000000000000000000000000000002000000000libsecret-0.21.7/.gitlab-ci.ymlinclude: - remote: 'https://gitlab.gnome.org/Infrastructure/freedesktop-ci-templates/-/raw/145b1bc7ef1702d2bd71584010d7113c6786a506/templates/fedora.yml' - component: gitlab.gnome.org/GNOME/citemplates/release-service@master inputs: dist-job-name: "build-release-tarball" tarball-artifact-path: "${TARBALL_ARTIFACT_PATH}" stages: - prepare - build - deploy variables: FDO_UPSTREAM_REPO: gnome/libsecret TARBALL_ARTIFACT_PATH: "_build/meson-dist/${CI_PROJECT_NAME}-${CI_COMMIT_TAG}.tar.xz" CPPCHECK_OPTIONS: "--enable=warning --enable=style --enable=performance --enable=portability --std=c99 --template='{id}:{file}:{line},{severity},{message}'" .fedora.container.common: variables: # When branching a stable release, change 'main' to the # release branch name to ensure that a new image will # be created, tailored for the stable branch. BRANCH_NAME: 'main' CONTAINER_TAG: '2025-01-15.0' FEDORA_VERSION: latest # Derive FDO variables from this automatically. # DO NOT edit, instead change the variables above FDO_REPO_SUFFIX: '${BRANCH_NAME}' FDO_DISTRIBUTION_TAG: '${CONTAINER_TAG}-fedora-${FEDORA_VERSION}' FDO_DISTRIBUTION_VERSION: '${FEDORA_VERSION}' ############################################# # Create CI Docker Images # ############################################# # Temporarily set a dummy container build for the FDO GitLab migration, which is down .dummy-container-build: script: - echo Dummy container build # See also https://gitlab.gnome.org/Infrastructure/freedesktop-ci-templates build.container.fedora@x86_64: extends: # - '.fdo.container-build@fedora' - .dummy-container-build - '.fedora.container.common' stage: prepare variables: # no need to pull the whole tree for rebuilding the image GIT_STRATEGY: none # Expiry sets fdo.expires on the image FDO_EXPIRES_AFTER: 8w FDO_DISTRIBUTION_PACKAGES: >- clang-analyzer cppcheck dbus-x11 diffutils docbook-style-xsl gettext gi-docgen git gjs glib2-devel gnutls-devel gobject-introspection-devel lcov libasan libgcrypt-devel libpamtest-devel libubsan libxslt meson pam-devel pam_wrapper python3-dbus python3-gobject redhat-rpm-config swtpm swtpm-tools tpm2-abrmd tpm2-tss-devel vala valgrind-devel ############################################# # STAGE: BUILD # ############################################# .build: extends: - '.fdo.suffixed-image@fedora' - '.fedora.container.common' parallel: matrix: - CRYPTO: libgcrypt - CRYPTO: gnutls GNUTLS_FORCE_FIPS_MODE: [0, 1] - CRYPTO: disabled fedora:Werror: stage: build extends: - .build script: - meson _build -Dwerror=true -Dc_args=-Wno-error=deprecated-declarations -Dgtk_doc=false -Dcrypto=$CRYPTO - meson compile -C _build - meson test -C _build --print-errorlogs artifacts: reports: junit: "_build/meson-logs/testlog.junit.xml" name: "libsecret-werror-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" when: always paths: - "_build/config.h" - "_build/meson-logs" fedora:asan: stage: build extends: - .build script: - export LSAN_OPTIONS=suppressions=$PWD/build/lsan.supp - meson _build -Db_sanitize=address -Dgtk_doc=false -Dintrospection=false -Dcrypto=$CRYPTO - meson compile -C _build - meson test -C _build --print-errorlogs artifacts: reports: junit: "_build/meson-logs/testlog.junit.xml" name: "libsecret-asan-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" when: always paths: - "_build/config.h" - "_build/meson-logs" fedora:ubsan: stage: build extends: - .build script: - meson _build -Db_sanitize=undefined -Dgtk_doc=false -Dcrypto=$CRYPTO - meson compile -C _build - meson test -C _build --print-errorlogs artifacts: reports: junit: "_build/meson-logs/testlog.junit.xml" name: "libsecret-ubsan-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" when: always paths: - "_build/config.h" - "_build/meson-logs" fedora-static-analyzers/test: stage: build extends: - .build script: - meson _build -Dgtk_doc=false -Dcrypto=$CRYPTO - meson compile -C _build --ninja-args scan-build - cppcheck --force -q $CPPCHECK_OPTIONS libsecret/ egg/ tool/ artifacts: when: on_failure paths: - _build/meson-logs/testlog.txt fedora:PAM: stage: build extends: - .build script: - meson _build -Dwerror=true -Dc_args=-Wno-error=deprecated-declarations -Dgtk_doc=false -Dpam=true - meson compile -C _build - meson test -C _build --print-errorlogs artifacts: reports: junit: "_build/meson-logs/testlog.junit.xml" name: "libsecret-pam-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" when: always paths: - "_build/config.h" - "_build/meson-logs" fedora:coverage: extends: - '.fdo.suffixed-image@fedora' - '.fedora.container.common' stage: build script: - meson _build -Db_coverage=true -Dtpm2=true -Dgtk_doc=false - meson compile -C _build - export XDG_CONFIG_HOME=$HOME/.config - /usr/share/swtpm/swtpm-create-user-config-files --root - mkdir -p ${XDG_CONFIG_HOME}/mytpm1 - swtpm_setup --tpm2 --tpmstate $XDG_CONFIG_HOME/mytpm1 --createek --allow-signing --decryption --create-ek-cert --create-platform-cert --lock-nvram --overwrite --display - swtpm socket --tpm2 --tpmstate dir=$XDG_CONFIG_HOME/mytpm1 --flags startup-clear --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --daemon - 'tpm2-abrmd --logger=stdout --tcti=swtpm: --session --allow-root --flush-all &' - 'export TCTI=tabrmd:bus_type=session' - meson test -C _build --print-errorlogs - ninja coverage-html -C _build coverage: '/^\s+lines.+:\s+([\d.]+\%)\s+/' artifacts: name: "libsecret-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" when: on_success paths: - _build/meson-logs/coveragereport/ # https://github.com/linux-test-project/lcov/issues/58 allow_failure: true reference: extends: - '.fdo.suffixed-image@fedora' - '.fedora.container.common' stage: build variables: MESON_ARGS: >- -Dgtk_doc=true -Dvapi=false -Dmanpage=false script: - meson ${MESON_ARGS} _build - ninja -C _build - mv _build/docs/reference/libsecret/libsecret-1 _reference artifacts: paths: - _reference ############################################# # STAGE: DEPLOY # ############################################# build-release-tarball: extends: - '.fdo.suffixed-image@fedora' - '.fedora.container.common' stage: deploy script: - meson setup _build - meson dist -C _build artifacts: paths: - $TARBALL_ARTIFACT_PATH pages: stage: deploy script: - mkdir public - mv _build/meson-logs/coveragereport public/coverage - mv _reference/* public/ artifacts: when: on_success paths: - public # https://github.com/linux-test-project/lcov/issues/58 allow_failure: true 07070100000003000081A400000000000000000000000167D9F0D9000067A1000000000000000000000000000000000000001900000000libsecret-0.21.7/COPYING 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. Copyright (C) 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. , 1 April 1990 Ty Coon, President of Vice That's all there is to it!07070100000004000081A400000000000000000000000167D9F0D900007B72000000000000000000000000000000000000001F00000000libsecret-0.21.7/COPYING.TESTSVarious portions of the libsecret tests are licensed under different open source licenses. See the top of the file/test in question for the exact license that applies. The full text of the various applicable licenses are listed here as required by those licenses: -------------------------------------------------------------------------- Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -------------------------------------------------------------------------- Copyright (C) 2000-2010 Julian Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. 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. -------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. 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. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License.07070100000005000081A400000000000000000000000167D9F0D900002609000000000000000000000000000000000000001600000000libsecret-0.21.7/NEWS0.21.7 * docs: Fix return comment of secret_value_get_text [#92] * bash-completion: Fix man section number in secret-tool completion file [!160] * bash-completion: Integrate external extended bash-completion script [!161] * bash-completion: Require minimal version for bash-completion [!163] * meson: Use newlines for build options 0.21.6 * meson: Make dbus-run-session optional [!157] * meson: Actually include bash-completion subdir [!158] 0.21.5 * session: Tolerate non-approved DH parameter usage in FIPS mode [!145] * Add some missing GIR annotations [!140] * meson: Create default test setup with D-Bus [!115] * meson: Use env.prepend() for test environment setup [!141] * meson: Fix license field [!139] * build: Remove self-inclusion from secret-item.h [!149] * build: Fix compiler warnings in Vala tests [!153] * tests: Fix "\|" used in test-secret-tool.sh not portable [!150] * Fix typo in D-Bus XML [!152] * docs: Fix minor gi-docgen reference [!142] * docs: Fix Python example [!144] * docs: Mention file backend [!146] * docs: Fix link in README [!147] * Several CI-related updates * Updated translations 0.21.4 * file-backend: Subscribe before calling dbus [!138] * meson: Fix crypto option being silently ignored [!137] * Updated translations 0.21.3 * Port PAM module from gnome-keyring [!128] * secret-tool: Fix memory issues in lock command [!134] 0.21.2 * Support GnuTLS as an alternative crypto backend [!122] * Fix LeakSanitizer issues [!126] * secret-tool: Verify that the parsed stdin password is vaild UTF-8 [!130] * Fix markup syntax for SecretSchema [!131] * Public secret_attributes_validate method [!129] * Updated translations 0.21.1 * Fix updating credentials by another process in the same Flatpak sandbox [#62, !99] * Migrate to g_memdup2 [!121] * Print error logs in CI [!125] * Updated translations 0.21.0 * Unlock the keyring before getting secret attributes [!105] * file-backend: avoid deadlock when portal op is canceled [!118, !120] * Properly chain-up GTasks around GDBusProxy::init_async [!106] * Fix nullable in secret_collection_for_alias_* [!110] * Fix finish function for searchv [!112] * secret-paths: Fix a little memory leak [!109] * Stop using GSlice [!116] * docs: port to gi-docgen [!101] * docs: fix example in usage docs [!117] * Several CI fixes [!111, !114] * Updated translations 0.20.5 * Drop autotools-based build [!44] * Use G_GNUC_NULL_TERMINATED where appropriate [!65] * collection, methods, prompt: Port to GTask [!66, !93] * Detect local storage in snaps in the same way as flatpaks [!67] * Add bash-completion for secret-tool [!70, #50, !72] * secret-tool: Add locking capabilities to secret tool [#28, !75] * secret-file-backend: Avoid closing the same file descriptor twice [!78] * Add support for TPM2 based secret storage [!83, !90, !95] * Create default collection after DBus.Error.UnknownObject [!94] * Port documentation to gi-docgen [!101] * GI annotation and documentation fixes [!63, !64, !102, !103, #66] * Build fixes [#54, !62, !68, #59, !73, !77, !82, !84, !85, !88] * Updated translations 0.20.4 * secret-file-collection: Make MAC comparison constant time [!60] * Initialize libgcrypt for SecretFileCollection [!56] * meson: Add tests for GIR-based languages [!54] * man: Add a bugtracker section to the manpage [!14] * meson: add option introspection [!53] * Updated translations 0.20.3 * secret-file-backend: Fix use-after-free in flatpak [!52] * docs: Add man subdir only if manpage is enabled [!51] 0.20.2 * secret-file-collection: force little-endian in GVariant [!49, #42] * Prefer g_info() over g_message() [!48, #40] * meson: Don't specify shared_library() [!47] * docs: Make sure to set install: true [!46] 0.20.1 * Build fixes [!45] 0.20.0 * secret-backend: New interface to represent password storage backend [!34] * secret-backend: Add local-storage backend [!6] * item: Port to GTask [!43] * Build fixes [!34, !37, !38, !40, !41, !42, ...] * Updated translations 0.19.1 * service: Fix secret_service_ensure_session_finish error propagation [!36] 0.19.0 * secret-password: Add necessary functions to migrate from D-Bus based API [!32] * egg: Request that secure memory not be dumped to disk [!30] * Add version macros [!29] * Add missing GType to flags in .gir [!16, !19] * paths: Port from GSimpleAsyncResult to GTask [!26] * build: Bump meson_version to 0.50 [!18, !35] * Build and test fixes [!15, !20, !21, !23, !33, ...] 0.18.8 * Add support for g_autoptr() to our types [!11] * Remove deprecated g_type_class_add_private() [!14] * Bump GLib dependency (2.44+) * Add meson build support [!9] * Fix vapi generation [!15, ...] * Build fixes [!12, !13] * Updated translations 0.18.7 * Migrate from intltool to gettext [!2] * Fix uninitialized memory returned by secret_item_get_schema_name() [#15] * secret-session: Avoid double-free in service_encode_plain_secret() * Port tap script to Python 3 [!4] * Build and test fixes [#734630] * Updated translations 0.18.6 * Fix shared key derivation between libsecret and gnome-keyring [#778357] * Avoid run-time error when gnome-keyring is not responding [#787391] * Enable cross compilation [#748111] * Port build scripts to Python 3 [#687637] * Build and test fixes [#767002, #777826, #734630, #768112] * GI annotation fixes [#785034] * Fix textual typos [#782206, ...] * Updated translations 0.18.5 * Build fixes * Port tests to Python 3 [#761834] * Fix textual typos [#763143] * Updated translations 0.18.4 * Multithreading fixes [#756766] * Fix memory leaks [#756766] * Updated translations 0.18.3 * Updated translations * Documentation fixes 0.18.2 * Testing fixes * Documentation typo [#747654 ...] * Build fixes [#743444] * Updated translations * Accommodate libgcrypt 1.6+ 0.18.1 * Testing fix [#726909] 0.18 * Mark most of unstable API as stable * Bump Glib dependency (2.38+) * Add secret_service_encode_dbus_secret() and decode functions * Use TAP for testing, parallel tests, and non-recursive make * Updated FSF's address * Remove unstable vapi [#721429] * Build fixes [#720087 #720244 #707452] * Updated translations 0.16 * Clarify documentation for secret_service_clear_xxx() [#705629] * Pass return_type to prompt async begin functions, rather than finish * Simpler way to use custom service/collection/item types * service: Rename secret_service_new() and friends to xxx_open() * Add secret_value_get_text() function to return NULL terminated secret * Fix return types in secret_service_search_finish() on error paths [#698040] * Testing fixes [#705202] * Build fixes [#704233] * Updated translations 0.15 * Tweak predefined schemas [#695791] * Updated translations 0.14 * Add a 'search' command to the tool for looking up items [#693881] * Try to unlock locked collection when storing an item [#693723] * Improve validation of the attributes table [#694107] * Allow empty SecretValue contents [#694787] * Introspection fixes [#694448] * Updated translations 0.13 * Updated translations * Build fixes 0.12 * When storing a secret, create default keyring if necessary * Share the memory pool with the gcr or libgnome-keyring library. * Testing and other fixes * Build fixes 0.11 * Better critical preconditions for invalid attributes 0.10 * Updated translations 0.9 * Add a manual page for secret-tool * Fix up libsecret licensing * Build and testing fixes 0.8 * Fix up libsecret licensing * Initialize gettext correctly * Fix crash in secret-tool * Build and testing fixes 0.7 * Match schema names for notes and network passwords * Add flags argument to secret_collection_for_alias() * Correct flags behavior for SecretCollection * Build fixes 0.6 * Rename secret_password_remove() to secret_password_clear() and similar names for related functions. * The secret_attribute_build() functions are stable * The predefined secret schemas are stable * Build fixes 0.5 * secret_service_remove() removes all unlocked matching items * Make sure that we have some attributes when searching * Add flags for item and collection creation * Add way to get schema name from a SecretItem * Rename secret_service_read_alias() to secret_collection_for_alias() * Split the stable and unstable APIs into separate pkg-config files, girs and vapis * Bump the library major version number to 1 * Document how to migrate from libgnome-keyring * Document how to use libsecret from C, js, python, vala * Documentation fixes 0.4 * Implement per collection search * Register secret service errors as GDBus errors * Cache default SecretService object, and provide a way to 'disconnect' it. Also 'disconnect' if service goes away. * Better use of aliases when storing passwords * Rename functions that operate on a dbus object path * Accept NULL as a SecretService parameter for many methods * Make loading items for a collection optional * More consistent use of schemas * Able to unlock and load secrets while searching for items * Cache the secret value on SecretItem * Add vala bindings and tests * Remove most varargs other than the simple password functions * Add SECRET_SCHEMA_NOTE schema * Lots of bug fixes * Documentation fixes * Testing fixes * Build fixes 0.3 * Add methods to get services from collections, items * Add methods to read and set aliases * Add methods which handle prompts for a DBus object path * Header path fix * Documentation fixes 0.2 * Fix header copyright issues * Build fixes * Add missing 'authtype' attribute to the 'network' schema * Add secret-schemas.h to the 'stable' API 0.1 * Initial release, not yet stable 07070100000006000081A400000000000000000000000167D9F0D9000009AF000000000000000000000000000000000000001B00000000libsecret-0.21.7/README.mdlibsecret ========= A [GObject]-based library for storing and receiving secrets. libsecret provides a convenient wrapper around two different mechanisms: If available, secrets are stored in the freedesktop [secret service]. Otherwise, secrets are stored in a file that is encrypted using a master secret that was provided by the [secret portal]. Documentation -------- You can find the nightly documentation at https://gnome.pages.gitlab.gnome.org/libsecret/. Building -------- To build, test and install libsecret, you can use the following commands: ``` $ meson setup _build $ meson compile -C _build $ meson test -C _build $ meson install -C _build ``` Contributing ------------- You can browse the code, issues and more at libsecret's [GitLab repository]. If you find a bug in libsecret, please file an issue on the [issue tracker]. Please try to add reproducible steps and the relevant version of libsecret. If you want to contribute functionality or bug fixes, please open a Merge Request (MR). For more info on how to do this, see GitLab's [help pages on MR's]. If libsecret is not translated in your language or you believe that the current translation has errors, you can join one of the various translation teams in GNOME. Translators do not commit directly to Git, but are advised to use our separate translation infrastructure instead. More info can be found at the [translation project wiki page]. Releases ------------- The release tarballs use [semantic versioning] since 0.19.0, which basically means: - The major version will be incremented if backward incompatible changes are added - The minor version will be incremented if new functionality is added in a backward compatible manner - The patch version will be incremented if only backward compatible bug fixes are added Note that there is no stable/unstable indication in whether the minor version number is even or odd. [GObject]: https://developer.gnome.org/gobject/stable/ [secret service]: https://specifications.freedesktop.org/secret-service-spec/ [secret portal]: https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Secret.html [GitLab repository]: https://gitlab.gnome.org/GNOME/libsecret [help pages on MR's]: https://docs.gitlab.com/ee/gitlab-basics/add-merge-request.html [issue tracker]: https://gitlab.gnome.org/GNOME/libsecret/issues [translation project wiki page]: https://wiki.gnome.org/TranslationProject/ [semantic versioning]: https://semver.org 07070100000007000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000002100000000libsecret-0.21.7/bash-completion07070100000008000081A400000000000000000000000167D9F0D9000001B2000000000000000000000000000000000000002D00000000libsecret-0.21.7/bash-completion/meson.buildbashcompdir = get_option('bashcompdir') if bashcompdir == '' bashcomp = dependency('bash-completion', version: '>= 2.12', required: get_option('bash_completion')) if bashcomp.found() bashcompdir = bashcomp.get_pkgconfig_variable('completionsdir') else message('Won\'t install bash completion due to missing dependencies') endif endif if bashcompdir != '' install_data('secret-tool', install_dir: bashcompdir) endif 07070100000009000081A400000000000000000000000167D9F0D9000005E6000000000000000000000000000000000000002D00000000libsecret-0.21.7/bash-completion/secret-tool# bash completion for secret-tool(1) -*- shell-script -*- _comp_cmd_secret_tool() { local cur prev words cword was_split comp_args _comp_initialize -s -- "$@" || return [[ $was_split ]] && return local -i i local mode="" has_mode="" word for i in ${!words[*]}; do if [[ $i -gt 0 && ${words[i]} != -* ]]; then ((i != cword)) && mode=${words[i]} has_mode=set break fi done if [[ ! $has_mode ]]; then # generate modes _comp_compgen_split -- "$("$1" nonexistent-mode 2>&1 | while read -r first second third rest; do if [[ $first == "${1##*/}" ]]; then printf "%s\n" "$second" elif [[ $first == usage: && $second == "${1##*/}" ]]; then printf "%s\n" "$third" fi done)" return fi case $mode in store) if [[ ${words[*]} != *\ --label[\ =]* ]]; then _comp_compgen -- -W "--label=" [[ ${COMPREPLY-} == *= ]] && compopt -o nospace fi ;; search) local -A opts=([--all]="" [--unlock]="") for word in "${words[@]:2}"; do [[ $word ]] && unset -v 'opts[$word]' done ((${#opts[@]})) && _comp_compgen -- -W '"${!opts[@]}"' ;; esac } && complete -F _comp_cmd_secret_tool secret-tool # ex: filetype=sh 0707010000000A000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000001700000000libsecret-0.21.7/build0707010000000B000081A400000000000000000000000167D9F0D900000053000000000000000000000000000000000000002100000000libsecret-0.21.7/build/lsan.supp# https://gitlab.gnome.org/GNOME/glib/-/issues/2312 leak:async_initable_init_first 0707010000000C000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000002000000000libsecret-0.21.7/build/valgrind0707010000000D000081A400000000000000000000000167D9F0D9000038EA000000000000000000000000000000000000002B00000000libsecret-0.21.7/build/valgrind/memcheck.h /* ---------------------------------------------------------------- Notice that the following BSD-style license applies to this one file (memcheck.h) only. The rest of Valgrind is licensed under the terms of the GNU General Public License, version 2, unless otherwise indicated. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- This file is part of MemCheck, a heavyweight Valgrind tool for detecting memory errors. Copyright (C) 2000-2015 Julian Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. 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. ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (memcheck.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- */ #ifndef __MEMCHECK_H #define __MEMCHECK_H /* This file is for inclusion into client (your!) code. You can use these macros to manipulate and query memory permissions inside your own programs. See comment near the top of valgrind.h on how to use them. */ #include "valgrind.h" /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ typedef enum { VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'), VG_USERREQ__MAKE_MEM_UNDEFINED, VG_USERREQ__MAKE_MEM_DEFINED, VG_USERREQ__DISCARD, VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, VG_USERREQ__CHECK_MEM_IS_DEFINED, VG_USERREQ__DO_LEAK_CHECK, VG_USERREQ__COUNT_LEAKS, VG_USERREQ__GET_VBITS, VG_USERREQ__SET_VBITS, VG_USERREQ__CREATE_BLOCK, VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */ VG_USERREQ__COUNT_LEAK_BLOCKS, VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE, VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE, /* This is just for memcheck's internal use - don't use it */ _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR = VG_USERREQ_TOOL_BASE('M','C') + 256 } Vg_MemCheckClientRequest; /* Client-code macros to manipulate the state of memory. */ /* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */ #define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__MAKE_MEM_NOACCESS, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Similarly, mark memory at _qzz_addr as addressable but undefined for _qzz_len bytes. */ #define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__MAKE_MEM_UNDEFINED, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Similarly, mark memory at _qzz_addr as addressable and defined for _qzz_len bytes. */ #define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__MAKE_MEM_DEFINED, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is not altered: bytes which are addressable are marked as defined, but those which are not addressable are left unchanged. */ #define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Create a block-description handle. The description is an ascii string which is included in any messages pertaining to addresses within the specified memory range. Has no other effect on the properties of the memory range. */ #define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CREATE_BLOCK, \ (_qzz_addr), (_qzz_len), (_qzz_desc), \ 0, 0) /* Discard a block-description-handle. Returns 1 for an invalid handle, 0 for a valid handle. */ #define VALGRIND_DISCARD(_qzz_blkindex) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__DISCARD, \ 0, (_qzz_blkindex), 0, 0, 0) /* Client-code macros to check the state of memory. */ /* Check that memory at _qzz_addr is addressable for _qzz_len bytes. If suitable addressibility is not established, Valgrind prints an error message and returns the address of the first offending byte. Otherwise it returns zero. */ #define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Check that memory at _qzz_addr is addressable and defined for _qzz_len bytes. If suitable addressibility and definedness are not established, Valgrind prints an error message and returns the address of the first offending byte. Otherwise it returns zero. */ #define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__CHECK_MEM_IS_DEFINED, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Use this macro to force the definedness and addressibility of an lvalue to be checked. If suitable addressibility and definedness are not established, Valgrind prints an error message and returns the address of the first offending byte. Otherwise it returns zero. */ #define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue) \ VALGRIND_CHECK_MEM_IS_DEFINED( \ (volatile unsigned char *)&(__lvalue), \ (unsigned long)(sizeof (__lvalue))) /* Do a full memory leak check (like --leak-check=full) mid-execution. */ #define VALGRIND_DO_LEAK_CHECK \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ 0, 0, 0, 0, 0) /* Same as VALGRIND_DO_LEAK_CHECK but only showing the entries for which there was an increase in leaked bytes or leaked nr of blocks since the previous leak search. */ #define VALGRIND_DO_ADDED_LEAK_CHECK \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ 0, 1, 0, 0, 0) /* Same as VALGRIND_DO_ADDED_LEAK_CHECK but showing entries with increased or decreased leaked bytes/blocks since previous leak search. */ #define VALGRIND_DO_CHANGED_LEAK_CHECK \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ 0, 2, 0, 0, 0) /* Do a summary memory leak check (like --leak-check=summary) mid-execution. */ #define VALGRIND_DO_QUICK_LEAK_CHECK \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ 1, 0, 0, 0, 0) /* Return number of leaked, dubious, reachable and suppressed bytes found by all previous leak checks. They must be lvalues. */ #define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed) \ /* For safety on 64-bit platforms we assign the results to private unsigned long variables, then assign these to the lvalues the user specified, which works no matter what type 'leaked', 'dubious', etc are. We also initialise '_qzz_leaked', etc because VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as defined. */ \ { \ unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ VALGRIND_DO_CLIENT_REQUEST_STMT( \ VG_USERREQ__COUNT_LEAKS, \ &_qzz_leaked, &_qzz_dubious, \ &_qzz_reachable, &_qzz_suppressed, 0); \ leaked = _qzz_leaked; \ dubious = _qzz_dubious; \ reachable = _qzz_reachable; \ suppressed = _qzz_suppressed; \ } /* Return number of leaked, dubious, reachable and suppressed bytes found by all previous leak checks. They must be lvalues. */ #define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \ /* For safety on 64-bit platforms we assign the results to private unsigned long variables, then assign these to the lvalues the user specified, which works no matter what type 'leaked', 'dubious', etc are. We also initialise '_qzz_leaked', etc because VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as defined. */ \ { \ unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ VALGRIND_DO_CLIENT_REQUEST_STMT( \ VG_USERREQ__COUNT_LEAK_BLOCKS, \ &_qzz_leaked, &_qzz_dubious, \ &_qzz_reachable, &_qzz_suppressed, 0); \ leaked = _qzz_leaked; \ dubious = _qzz_dubious; \ reachable = _qzz_reachable; \ suppressed = _qzz_suppressed; \ } /* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it into the provided zzvbits array. Return values: 0 if not running on valgrind 1 success 2 [previously indicated unaligned arrays; these are now allowed] 3 if any parts of zzsrc/zzvbits are not addressable. The metadata is not copied in cases 0, 2 or 3 so it should be impossible to segfault your system by using this call. */ #define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__GET_VBITS, \ (const char*)(zza), \ (char*)(zzvbits), \ (zznbytes), 0, 0) /* Set the validity data for addresses [zza..zza+zznbytes-1], copying it from the provided zzvbits array. Return values: 0 if not running on valgrind 1 success 2 [previously indicated unaligned arrays; these are now allowed] 3 if any parts of zza/zzvbits are not addressable. The metadata is not copied in cases 0, 2 or 3 so it should be impossible to segfault your system by using this call. */ #define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__SET_VBITS, \ (const char*)(zza), \ (const char*)(zzvbits), \ (zznbytes), 0, 0 ) /* Disable and re-enable reporting of addressing errors in the specified address range. */ #define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE, \ (_qzz_addr), (_qzz_len), 0, 0, 0) #define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE, \ (_qzz_addr), (_qzz_len), 0, 0, 0) #endif 0707010000000E000081A400000000000000000000000167D9F0D900066A5B000000000000000000000000000000000000002B00000000libsecret-0.21.7/build/valgrind/valgrind.h/* -*- c -*- ---------------------------------------------------------------- Notice that the following BSD-style license applies to this one file (valgrind.h) only. The rest of Valgrind is licensed under the terms of the GNU General Public License, version 2, unless otherwise indicated. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- This file is part of Valgrind, a dynamic binary instrumentation framework. Copyright (C) 2000-2015 Julian Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. 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. ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (valgrind.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- */ /* This file is for inclusion into client (your!) code. You can use these macros to manipulate and query Valgrind's execution inside your own programs. The resulting executables will still run without Valgrind, just a little bit more slowly than they otherwise would, but otherwise unchanged. When not running on valgrind, each client request consumes very few (eg. 7) instructions, so the resulting performance loss is negligible unless you plan to execute client requests millions of times per second. Nevertheless, if that is still a problem, you can compile with the NVALGRIND symbol defined (gcc -DNVALGRIND) so that client requests are not even compiled in. */ #ifndef __VALGRIND_H #define __VALGRIND_H /* ------------------------------------------------------------------ */ /* VERSION NUMBER OF VALGRIND */ /* ------------------------------------------------------------------ */ /* Specify Valgrind's version number, so that user code can conditionally compile based on our version number. Note that these were introduced at version 3.6 and so do not exist in version 3.5 or earlier. The recommended way to use them to check for "version X.Y or later" is (eg) #if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ && (__VALGRIND_MAJOR__ > 3 \ || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) */ #define __VALGRIND_MAJOR__ 3 #define __VALGRIND_MINOR__ 11 #include /* Nb: this file might be included in a file compiled with -ansi. So we can't use C++ style "//" comments nor the "asm" keyword (instead use "__asm__"). */ /* Derive some tags indicating what the target platform is. Note that in this file we're using the compiler's CPP symbols for identifying architectures, which are different to the ones we use within the rest of Valgrind. Note, __powerpc__ is active for both 32 and 64-bit PPC, whereas __powerpc64__ is only active for the latter (on Linux, that is). Misc note: how to find out what's predefined in gcc by default: gcc -Wp,-dM somefile.c */ #undef PLAT_x86_darwin #undef PLAT_amd64_darwin #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64be_linux #undef PLAT_ppc64le_linux #undef PLAT_arm_linux #undef PLAT_arm64_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux #undef PLAT_tilegx_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris #if defined(__APPLE__) && defined(__i386__) # define PLAT_x86_darwin 1 #elif defined(__APPLE__) && defined(__x86_64__) # define PLAT_amd64_darwin 1 #elif (defined(__MINGW32__) && !defined(__MINGW64__)) \ || defined(__CYGWIN32__) \ || (defined(_WIN32) && defined(_M_IX86)) # define PLAT_x86_win32 1 #elif defined(__MINGW64__) \ || (defined(_WIN64) && defined(_M_X64)) # define PLAT_amd64_win64 1 #elif defined(__linux__) && defined(__i386__) # define PLAT_x86_linux 1 #elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__) # define PLAT_amd64_linux 1 #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) # define PLAT_ppc32_linux 1 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF != 2 /* Big Endian uses ELF version 1 */ # define PLAT_ppc64be_linux 1 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF == 2 /* Little Endian uses ELF version 2 */ # define PLAT_ppc64le_linux 1 #elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__) # define PLAT_arm_linux 1 #elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__) # define PLAT_arm64_linux 1 #elif defined(__linux__) && defined(__s390__) && defined(__s390x__) # define PLAT_s390x_linux 1 #elif defined(__linux__) && defined(__mips__) && (__mips==64) # define PLAT_mips64_linux 1 #elif defined(__linux__) && defined(__mips__) && (__mips!=64) # define PLAT_mips32_linux 1 #elif defined(__linux__) && defined(__tilegx__) # define PLAT_tilegx_linux 1 #elif defined(__sun) && defined(__i386__) # define PLAT_x86_solaris 1 #elif defined(__sun) && defined(__x86_64__) # define PLAT_amd64_solaris 1 #else /* If we're not compiling for our target platform, don't generate any inline asms. */ # if !defined(NVALGRIND) # define NVALGRIND 1 # endif #endif /* ------------------------------------------------------------------ */ /* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ /* in here of use to end-users -- skip to the next section. */ /* ------------------------------------------------------------------ */ /* * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client * request. Accepts both pointers and integers as arguments. * * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind * client request that does not return a value. * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind * client request and whose value equals the client request result. Accepts * both pointers and integers as arguments. Note that such calls are not * necessarily pure functions -- they may have side effects. */ #define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \ _zzq_request, _zzq_arg1, _zzq_arg2, \ _zzq_arg3, _zzq_arg4, _zzq_arg5) \ do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) #define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \ _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) #if defined(NVALGRIND) /* Define NVALGRIND to completely remove the Valgrind magic sequence from the compiled code (analogous to NDEBUG's effects on assert()) */ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ (_zzq_default) #else /* ! NVALGRIND */ /* The following defines the magic code sequences which the JITter spots and handles magically. Don't look too closely at them as they will rot your brain. The assembly code sequences for all architectures is in this one file. This is because this file must be stand-alone, and we don't want to have multiple files. For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default value gets put in the return slot, so that everything works when this is executed not under Valgrind. Args are passed in a memory block, and so there's no intrinsic limit to the number that could be passed, but it's currently five. The macro args are: _zzq_rlval result lvalue _zzq_default default value (result returned when running on real CPU) _zzq_request request code _zzq_arg1..5 request params The other two macros are used to support function wrapping, and are a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the guest's NRADDR pseudo-register and whatever other information is needed to safely run the call original from the wrapper: on ppc64-linux, the R2 value at the divert point is also needed. This information is abstracted into a user-visible type, OrigFn. VALGRIND_CALL_NOREDIR_* behaves the same as the following on the guest, but guarantees that the branch instruction will not be redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a complete inline asm, since it needs to be combined with more magic inline asm stuff to be useful. */ /* ----------------- x86-{linux,darwin,solaris} ---------------- */ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || (defined(PLAT_x86_win32) && defined(__GNUC__)) \ || defined(PLAT_x86_solaris) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "roll $3, %%edi ; roll $13, %%edi\n\t" \ "roll $29, %%edi ; roll $19, %%edi\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EDX = client_request ( %EAX ) */ \ "xchgl %%ebx,%%ebx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EAX = guest_NRADDR */ \ "xchgl %%ecx,%%ecx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_EAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%EAX */ \ "xchgl %%edx,%%edx\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "xchgl %%edi,%%edi\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) || PLAT_x86_solaris */ /* ------------------------- x86-Win32 ------------------------- */ #if defined(PLAT_x86_win32) && !defined(__GNUC__) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #if defined(_MSC_VER) #define __SPECIAL_INSTRUCTION_PREAMBLE \ __asm rol edi, 3 __asm rol edi, 13 \ __asm rol edi, 29 __asm rol edi, 19 #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \ (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \ (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \ (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5)) static __inline uintptr_t valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, uintptr_t _zzq_arg1, uintptr_t _zzq_arg2, uintptr_t _zzq_arg3, uintptr_t _zzq_arg4, uintptr_t _zzq_arg5) { volatile uintptr_t _zzq_args[6]; volatile unsigned int _zzq_result; _zzq_args[0] = (uintptr_t)(_zzq_request); _zzq_args[1] = (uintptr_t)(_zzq_arg1); _zzq_args[2] = (uintptr_t)(_zzq_arg2); _zzq_args[3] = (uintptr_t)(_zzq_arg3); _zzq_args[4] = (uintptr_t)(_zzq_arg4); _zzq_args[5] = (uintptr_t)(_zzq_arg5); __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default __SPECIAL_INSTRUCTION_PREAMBLE /* %EDX = client_request ( %EAX ) */ __asm xchg ebx,ebx __asm mov _zzq_result, edx } return _zzq_result; } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ /* %EAX = guest_NRADDR */ \ __asm xchg ecx,ecx \ __asm mov __addr, eax \ } \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_EAX ERROR #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ __asm xchg edi,edi \ } \ } while (0) #else #error Unsupported compiler. #endif #endif /* PLAT_x86_win32 */ /* ----------------- amd64-{linux,darwin,solaris} --------------- */ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) \ || (defined(PLAT_amd64_win64) && defined(__GNUC__)) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RDX = client_request ( %RAX ) */ \ "xchgq %%rbx,%%rbx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RAX = guest_NRADDR */ \ "xchgq %%rcx,%%rcx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_RAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%RAX */ \ "xchgq %%rdx,%%rdx\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "xchgq %%rdi,%%rdi\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ /* ------------------------- amd64-Win64 ------------------------- */ #if defined(PLAT_amd64_win64) && !defined(__GNUC__) #error Unsupported compiler. #endif /* PLAT_amd64_win64 */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rlwinm 0,0,3,0,31 ; rlwinm 0,0,13,0,31\n\t" \ "rlwinm 0,0,29,0,31 ; rlwinm 0,0,19,0,31\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned int _zzq_args[6]; \ unsigned int _zzq_result; \ unsigned int* _zzq_ptr; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64be_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ unsigned long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned long int _zzq_args[6]; \ unsigned long int _zzq_result; \ unsigned long int* _zzq_ptr; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc64be_linux */ #if defined(PLAT_ppc64le_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ unsigned long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned long int _zzq_args[6]; \ unsigned long int _zzq_result; \ unsigned long int* _zzq_ptr; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R12 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc64le_linux */ /* ------------------------- arm-linux ------------------------- */ #if defined(PLAT_arm_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("mov r3, %1\n\t" /*default*/ \ "mov r4, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* R3 = client_request ( R4 ) */ \ "orr r10, r10, r10\n\t" \ "mov %0, r3" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "cc","memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* R3 = guest_NRADDR */ \ "orr r11, r11, r11\n\t" \ "mov %0, r3" \ : "=r" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R4 */ \ "orr r12, r12, r12\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "orr r9, r9, r9\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_arm_linux */ /* ------------------------ arm64-linux ------------------------- */ #if defined(PLAT_arm64_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "ror x12, x12, #3 ; ror x12, x12, #13 \n\t" \ "ror x12, x12, #51 ; ror x12, x12, #61 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile("mov x3, %1\n\t" /*default*/ \ "mov x4, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* X3 = client_request ( X4 ) */ \ "orr x10, x10, x10\n\t" \ "mov %0, x3" /*result*/ \ : "=r" (_zzq_result) \ : "r" ((unsigned long int)(_zzq_default)), \ "r" (&_zzq_args[0]) \ : "cc","memory", "x3", "x4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* X3 = guest_NRADDR */ \ "orr x11, x11, x11\n\t" \ "mov %0, x3" \ : "=r" (__addr) \ : \ : "cc", "memory", "x3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir X8 */ \ "orr x12, x12, x12\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "orr x9, x9, x9\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_arm64_linux */ /* ------------------------ s390x-linux ------------------------ */ #if defined(PLAT_s390x_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; /* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific * code. This detection is implemented in platform specific toIR.c * (e.g. VEX/priv/guest_s390_decoder.c). */ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "lr 15,15\n\t" \ "lr 1,1\n\t" \ "lr 2,2\n\t" \ "lr 3,3\n\t" #define __CLIENT_REQUEST_CODE "lr 2,2\n\t" #define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" #define __CALL_NO_REDIR_CODE "lr 4,4\n\t" #define __VEX_INJECT_IR_CODE "lr 5,5\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile(/* r2 = args */ \ "lgr 2,%1\n\t" \ /* r3 = default */ \ "lgr 3,%2\n\t" \ __SPECIAL_INSTRUCTION_PREAMBLE \ __CLIENT_REQUEST_CODE \ /* results = r3 */ \ "lgr %0, 3\n\t" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "2", "3", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __GET_NR_CONTEXT_CODE \ "lgr %0, 3\n\t" \ : "=a" (__addr) \ : \ : "cc", "3", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_R1 \ __SPECIAL_INSTRUCTION_PREAMBLE \ __CALL_NO_REDIR_CODE #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __VEX_INJECT_IR_CODE); \ } while (0) #endif /* PLAT_s390x_linux */ /* ------------------------- mips32-linux ---------------- */ #if defined(PLAT_mips32_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; /* .word 0x342 * .word 0x742 * .word 0xC2 * .word 0x4C2*/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "srl $0, $0, 13\n\t" \ "srl $0, $0, 29\n\t" \ "srl $0, $0, 3\n\t" \ "srl $0, $0, 19\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("move $11, %1\n\t" /*default*/ \ "move $12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* T3 = client_request ( T4 ) */ \ "or $13, $13, $13\n\t" \ "move %0, $11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$11", "$12"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %t9 = guest_NRADDR */ \ "or $14, $14, $14\n\t" \ "move %0, $11" /*result*/ \ : "=r" (__addr) \ : \ : "$11" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%t9 */ \ "or $15, $15, $15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or $11, $11, $11\n\t" \ ); \ } while (0) #endif /* PLAT_mips32_linux */ /* ------------------------- mips64-linux ---------------- */ #if defined(PLAT_mips64_linux) typedef struct { unsigned long nraddr; /* where's the code? */ } OrigFn; /* dsll $0,$0, 3 * dsll $0,$0, 13 * dsll $0,$0, 29 * dsll $0,$0, 19*/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "dsll $0,$0, 3 ; dsll $0,$0,13\n\t" \ "dsll $0,$0,29 ; dsll $0,$0,19\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile("move $11, %1\n\t" /*default*/ \ "move $12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* $11 = client_request ( $12 ) */ \ "or $13, $13, $13\n\t" \ "move %0, $11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$11", "$12"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* $11 = guest_NRADDR */ \ "or $14, $14, $14\n\t" \ "move %0, $11" /*result*/ \ : "=r" (__addr) \ : \ : "$11"); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir $25 */ \ "or $15, $15, $15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or $11, $11, $11\n\t" \ ); \ } while (0) #endif /* PLAT_mips64_linux */ /* ------------------------ tilegx-linux --------------- */ #if defined(PLAT_tilegx_linux) typedef struct { unsigned long long int nraddr; /* where's the code? */ } OrigFn; /*** special instruction sequence. 0:02b3c7ff91234fff { moveli zero, 4660 ; moveli zero, 22136 } 8:0091a7ff95678fff { moveli zero, 22136 ; moveli zero, 4660 } ****/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ ".quad 0x02b3c7ff91234fff\n" \ ".quad 0x0091a7ff95678fff\n" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ ({ volatile unsigned long long int _zzq_args[6]; \ volatile unsigned long long int _zzq_result; \ _zzq_args[0] = (unsigned long long int)(_zzq_request); \ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ __asm__ volatile("move r11, %1\n\t" /*default*/ \ "move r12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* r11 = client_request */ \ "or r13, r13, r13\n\t" \ "move %0, r11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "memory", "r11", "r12"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* r11 = guest_NRADDR */ \ "or r14, r14, r14\n" \ "move %0, r11\n" \ : "=r" (__addr) \ : \ : "memory", "r11" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_R12 \ __SPECIAL_INSTRUCTION_PREAMBLE \ "or r15, r15, r15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or r11, r11, r11\n\t" \ ); \ } while (0) #endif /* PLAT_tilegx_linux */ /* Insert assembly code for other platforms here... */ #endif /* NVALGRIND */ /* ------------------------------------------------------------------ */ /* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ /* ugly. It's the least-worst tradeoff I can think of. */ /* ------------------------------------------------------------------ */ /* This section defines magic (a.k.a appalling-hack) macros for doing guaranteed-no-redirection macros, so as to get from function wrappers to the functions they are wrapping. The whole point is to construct standard call sequences, but to do the call itself with a special no-redirect call pseudo-instruction that the JIT understands and handles specially. This section is long and repetitious, and I can't see a way to make it shorter. The naming scheme is as follows: CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} 'W' stands for "word" and 'v' for "void". Hence there are different macros for calling arity 0, 1, 2, 3, 4, etc, functions, and for each, the possibility of returning a word-typed result, or no result. */ /* Use these to write the name of your wrapper. NOTE: duplicates VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts the default behaviour equivalence class tag "0000" into the name. See pub_tool_redir.h for details -- normally you don't need to think about this, though. */ /* Use an extra level of macroisation so as to ensure the soname/fnname args are fully macro-expanded before pasting them together. */ #define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd #define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ VG_CONCAT4(_vgw00000ZU_,soname,_,fnname) #define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname) /* Use this macro from within a wrapper function to collect the context (address and possibly other info) of the original function. Once you have that you can then use it in one of the CALL_FN_ macros. The type of the argument _lval is OrigFn. */ #define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) /* Also provide end-user facilities for function replacement, rather than wrapping. A replacement function differs from a wrapper in that it has no way to get hold of the original function being called, and hence no way to call onwards to it. In a replacement function, VALGRIND_GET_ORIG_FN always returns zero. */ #define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \ VG_CONCAT4(_vgr00000ZU_,soname,_,fnname) #define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \ VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname) /* Derivatives of the main macros below, for calling functions returning void. */ #define CALL_FN_v_v(fnptr) \ do { volatile unsigned long _junk; \ CALL_FN_W_v(_junk,fnptr); } while (0) #define CALL_FN_v_W(fnptr, arg1) \ do { volatile unsigned long _junk; \ CALL_FN_W_W(_junk,fnptr,arg1); } while (0) #define CALL_FN_v_WW(fnptr, arg1,arg2) \ do { volatile unsigned long _junk; \ CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) #define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ do { volatile unsigned long _junk; \ CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) #define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ do { volatile unsigned long _junk; \ CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) #define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ do { volatile unsigned long _junk; \ CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) #define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ do { volatile unsigned long _junk; \ CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) #define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ do { volatile unsigned long _junk; \ CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) /* ----------------- x86-{linux,darwin,solaris} ---------------- */ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || defined(PLAT_x86_solaris) /* These regs are trashed by the hidden call. No need to mention eax as gcc can already see that, plus causes gcc to bomb. */ #define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "movl %%esp,%%edi\n\t" \ "andl $0xfffffff0,%%esp\n\t" #define VALGRIND_RESTORE_STACK \ "movl %%edi,%%esp\n\t" /* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 48(%%eax)\n\t" \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_x86_linux || PLAT_x86_darwin || PLAT_x86_solaris */ /* ---------------- amd64-{linux,darwin,solaris} --------------- */ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) /* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ "rdi", "r8", "r9", "r10", "r11" /* This is all pretty complex. It's so as to make stack unwinding work reliably. See bug 243270. The basic problem is the sub and add of 128 of %rsp in all of the following macros. If gcc believes the CFA is in %rsp, then unwinding may fail, because what's at the CFA is not what gcc "expected" when it constructs the CFIs for the places where the macros are instantiated. But we can't just add a CFI annotation to increase the CFA offset by 128, to match the sub of 128 from %rsp, because we don't know whether gcc has chosen %rsp as the CFA at that point, or whether it has chosen some other register (eg, %rbp). In the latter case, adding a CFI annotation to change the CFA offset is simply wrong. So the solution is to get hold of the CFA using __builtin_dwarf_cfa(), put it in a known register, and add a CFI annotation to say what the register is. We choose %rbp for this (perhaps perversely), because: (1) %rbp is already subject to unwinding. If a new register was chosen then the unwinder would have to unwind it in all stack traces, which is expensive, and (2) %rbp is already subject to precise exception updates in the JIT. If a new register was chosen, we'd have to have precise exceptions for it too, which reduces performance of the generated code. However .. one extra complication. We can't just whack the result of __builtin_dwarf_cfa() into %rbp and then add %rbp to the list of trashed registers at the end of the inline assembly fragments; gcc won't allow %rbp to appear in that list. Hence instead we need to stash %rbp in %r15 for the duration of the asm, and say that %r15 is trashed instead. gcc seems happy to go with that. Oh .. and this all needs to be conditionalised so that it is unchanged from before this commit, when compiled with older gccs that don't support __builtin_dwarf_cfa. Furthermore, since this header file is freestanding, it has to be independent of config.h, and so the following conditionalisation cannot depend on configure time checks. Although it's not clear from 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)', this expression excludes Darwin. .cfi directives in Darwin assembly appear to be completely different and I haven't investigated how they work. For even more entertainment value, note we have to use the completely undocumented __builtin_dwarf_cfa(), which appears to really compute the CFA, whereas __builtin_frame_address(0) claims to but actually doesn't. See https://bugs.kde.org/show_bug.cgi?id=243270#c47 */ #if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) # define __FRAME_POINTER \ ,"r"(__builtin_dwarf_cfa()) # define VALGRIND_CFI_PROLOGUE \ "movq %%rbp, %%r15\n\t" \ "movq %2, %%rbp\n\t" \ ".cfi_remember_state\n\t" \ ".cfi_def_cfa rbp, 0\n\t" # define VALGRIND_CFI_EPILOGUE \ "movq %%r15, %%rbp\n\t" \ ".cfi_restore_state\n\t" #else # define __FRAME_POINTER # define VALGRIND_CFI_PROLOGUE # define VALGRIND_CFI_EPILOGUE #endif /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "movq %%rsp,%%r14\n\t" \ "andq $0xfffffffffffffff0,%%rsp\n\t" #define VALGRIND_RESTORE_STACK \ "movq %%r14,%%rsp\n\t" /* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned long) == 8. */ /* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ macros. In order not to trash the stack redzone, we need to drop %rsp by 128 before the hidden call, and restore afterwards. The nastyness is that it is only by luck that the stack still appears to be unwindable during the hidden call - since then the behaviour of any routine using this macro does not match what the CFI data says. Sigh. Why is this important? Imagine that a wrapper has a stack allocated local, and passes to the hidden call, a pointer to it. Because gcc does not know about the hidden call, it may allocate that local in the redzone. Unfortunately the hidden call may then trash it before it comes to use it. So we must step clear of the redzone, for the duration of the hidden call, to make it safe. Probably the same problem afflicts the other redzone-style ABIs too (ppc64-linux); but for those, the stack is self describing (none of this CFI nonsense) so at least messing with the stack pointer doesn't give a danger of non-unwindable stack. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 96(%%rax)\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) /* This is useful for finding out about the on-stack stuff: extern int f9 ( int,int,int,int,int,int,int,int,int ); extern int f10 ( int,int,int,int,int,int,int,int,int,int ); extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); int g9 ( void ) { return f9(11,22,33,44,55,66,77,88,99); } int g10 ( void ) { return f10(11,22,33,44,55,66,77,88,99,110); } int g11 ( void ) { return f11(11,22,33,44,55,66,77,88,99,110,121); } int g12 ( void ) { return f12(11,22,33,44,55,66,77,88,99,110,121,132); } */ /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rlwinm 1,1,0,0,27\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc32-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg12 */ \ "lwz 3,48(11)\n\t" \ "stw 3,20(1)\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64be_linux) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rldicr 1,1,0,59\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg12 */ \ "ld 3,96(11)\n\t" \ "std 3,136(1)\n\t" \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64be_linux */ /* ------------------------- ppc64le-linux ----------------------- */ #if defined(PLAT_ppc64le_linux) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rldicr 1,1,0,59\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg11 */ \ "ld 3,88(12)\n\t" \ "std 3,112(1)\n\t" \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg12 */ \ "ld 3,96(12)\n\t" \ "std 3,120(1)\n\t" \ /* arg11 */ \ "ld 3,88(12)\n\t" \ "std 3,112(1)\n\t" \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64le_linux */ /* ------------------------- arm-linux ------------------------- */ #if defined(PLAT_arm_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4", "r12", "r14" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ /* This is a bit tricky. We store the original stack pointer in r10 as it is callee-saves. gcc doesn't allow the use of r11 for some reason. Also, we can't directly "bic" the stack pointer in thumb mode since r13 isn't an allowed register number in that context. So use r4 as a temporary, since that is about to get trashed anyway, just after each use of this macro. Side effect is we need to be very careful about any future changes, since VALGRIND_ALIGN_STACK simply assumes r4 is usable. */ #define VALGRIND_ALIGN_STACK \ "mov r10, sp\n\t" \ "mov r4, sp\n\t" \ "bic r4, r4, #7\n\t" \ "mov sp, r4\n\t" #define VALGRIND_RESTORE_STACK \ "mov sp, r10\n\t" /* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "push {r0} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "push {r0, r1} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "push {r0, r1, r2} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "push {r0, r1, r2, r3} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #40] \n\t" \ "push {r0} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #40] \n\t" \ "ldr r1, [%1, #44] \n\t" \ "push {r0, r1} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #40] \n\t" \ "ldr r1, [%1, #44] \n\t" \ "ldr r2, [%1, #48] \n\t" \ "push {r0, r1, r2} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_arm_linux */ /* ------------------------ arm64-linux ------------------------ */ #if defined(PLAT_arm64_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "x0", "x1", "x2", "x3","x4", "x5", "x6", "x7", "x8", "x9", \ "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", \ "x18", "x19", "x20", "x30", \ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", \ "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", \ "v26", "v27", "v28", "v29", "v30", "v31" /* x21 is callee-saved, so we can use it to save and restore SP around the hidden call. */ #define VALGRIND_ALIGN_STACK \ "mov x21, sp\n\t" \ "bic sp, x21, #15\n\t" #define VALGRIND_RESTORE_STACK \ "mov sp, x21\n\t" /* These CALL_FN_ macros assume that on arm64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x20 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x20 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x30 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1, #88] \n\t" \ "str x8, [sp, #16] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11, \ arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x30 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1, #88] \n\t" \ "str x8, [sp, #16] \n\t" \ "ldr x8, [%1, #96] \n\t" \ "str x8, [sp, #24] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_arm64_linux */ /* ------------------------- s390x-linux ------------------------- */ #if defined(PLAT_s390x_linux) /* Similar workaround as amd64 (see above), but we use r11 as frame pointer and save the old r11 in r7. r11 might be used for argvec, therefore we copy argvec in r1 since r1 is clobbered after the call anyway. */ #if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) # define __FRAME_POINTER \ ,"d"(__builtin_dwarf_cfa()) # define VALGRIND_CFI_PROLOGUE \ ".cfi_remember_state\n\t" \ "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ "lgr 7,11\n\t" \ "lgr 11,%2\n\t" \ ".cfi_def_cfa r11, 0\n\t" # define VALGRIND_CFI_EPILOGUE \ "lgr 11, 7\n\t" \ ".cfi_restore_state\n\t" #else # define __FRAME_POINTER # define VALGRIND_CFI_PROLOGUE \ "lgr 1,%1\n\t" # define VALGRIND_CFI_EPILOGUE #endif /* Nb: On s390 the stack pointer is properly aligned *at all times* according to the s390 GCC maintainer. (The ABI specification is not precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and VALGRIND_RESTORE_STACK are not defined here. */ /* These regs are trashed by the hidden call. Note that we overwrite r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the function a proper return address. All others are ABI defined call clobbers. */ #define __CALLER_SAVED_REGS "0","1","2","3","4","5","14", \ "f0","f1","f2","f3","f4","f5","f6","f7" /* Nb: Although r11 is modified in the asm snippets below (inside VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for two reasons: (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not modified (2) GCC will complain that r11 cannot appear inside a clobber section, when compiled with -O -fno-omit-frame-pointer */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 1, 0(1)\n\t" /* target->r1 */ \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) /* The call abi has the arguments in r2-r6 and stack */ #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1, arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-168\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,168\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-176\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,176\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-184\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,184\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-192\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,192\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-200\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,200\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10, arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-208\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "mvc 200(8,15), 88(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,208\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-216\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "mvc 200(8,15), 88(1)\n\t" \ "mvc 208(8,15), 96(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,216\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_s390x_linux */ /* ------------------------- mips32-linux ----------------------- */ #if defined(PLAT_mips32_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ "$25", "$31" /* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16\n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" /* arg1*/ \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 24\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 24 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 32\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "nop\n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 32 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 32\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 32 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 40\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 40 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 40\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 40 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 48\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 48 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 48\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 44(%1) \n\t" \ "sw $4, 40($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 48 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 56\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 44(%1) \n\t" \ "sw $4, 40($29) \n\t" \ "lw $4, 48(%1) \n\t" \ "sw $4, 44($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 56 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_mips32_linux */ /* ------------------------- mips64-linux ------------------------- */ #if defined(PLAT_mips64_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ "$25", "$31" /* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" /* arg1*/ \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "dsubu $29, $29, 8\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 8\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "dsubu $29, $29, 16\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 16\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "dsubu $29, $29, 24\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 88(%1)\n\t" \ "sd $4, 16($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 24\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "dsubu $29, $29, 32\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 88(%1)\n\t" \ "sd $4, 16($29)\n\t" \ "ld $4, 96(%1)\n\t" \ "sd $4, 24($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 32\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_mips64_linux */ /* ------------------------ tilegx-linux ------------------------- */ #if defined(PLAT_tilegx_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3", "r4", "r5", \ "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", \ "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", \ "r23", "r24", "r25", "r26", "r27", "r28", "r29", "lr" /* These CALL_FN_ macros assume that on tilegx-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "ld r12, %1 \n\t" /* target->r11 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0 \n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8 \n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */ \ "ld_add r9, r29, 8 \n\t" /*arg10 -> r9 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */ \ "ld_add r9, r29, 8 \n\t" /*arg10 -> r9 */ \ "ld r10, r29 \n\t" \ "st_add sp, r10, -16 \n\t" \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 24 \n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */ \ "ld_add r9, r29, 8 \n\t" /*arg10 -> r9 */ \ "addi r28, sp, -8 \n\t" \ "addi sp, sp, -24 \n\t" \ "ld_add r10, r29, 8 \n\t" \ "ld r11, r29 \n\t" \ "st_add r28, r10, 8 \n\t" \ "st r28, r11 \n\t" \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 32 \n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_tilegx_linux */ /* ------------------------------------------------------------------ */ /* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ /* */ /* ------------------------------------------------------------------ */ /* Some request codes. There are many more of these, but most are not exposed to end-user view. These are the public ones, all of the form 0x1000 + small_number. Core ones are in the range 0x00000000--0x0000ffff. The non-public ones start at 0x2000. */ /* These macros are used by tools -- they must be public, but don't embed them into other programs. */ #define VG_USERREQ_TOOL_BASE(a,b) \ ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) #define VG_IS_TOOL_USERREQ(a, b, v) \ (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ typedef enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, /* These allow any function to be called from the simulated CPU but run on the real CPU. Nb: the first arg passed to the function is always the ThreadId of the running thread! So CLIENT_CALL0 actually requires a 1 arg function, etc. */ VG_USERREQ__CLIENT_CALL0 = 0x1101, VG_USERREQ__CLIENT_CALL1 = 0x1102, VG_USERREQ__CLIENT_CALL2 = 0x1103, VG_USERREQ__CLIENT_CALL3 = 0x1104, /* Can be useful in regression testing suites -- eg. can send Valgrind's output to /dev/null and still count errors. */ VG_USERREQ__COUNT_ERRORS = 0x1201, /* Allows the client program and/or gdbserver to execute a monitor command. */ VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, /* These are useful and can be interpreted by any tool that tracks malloc() et al, by using vg_replace_malloc.c. */ VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b, VG_USERREQ__FREELIKE_BLOCK = 0x1302, /* Memory pool support. */ VG_USERREQ__CREATE_MEMPOOL = 0x1303, VG_USERREQ__DESTROY_MEMPOOL = 0x1304, VG_USERREQ__MEMPOOL_ALLOC = 0x1305, VG_USERREQ__MEMPOOL_FREE = 0x1306, VG_USERREQ__MEMPOOL_TRIM = 0x1307, VG_USERREQ__MOVE_MEMPOOL = 0x1308, VG_USERREQ__MEMPOOL_CHANGE = 0x1309, VG_USERREQ__MEMPOOL_EXISTS = 0x130a, /* Allow printfs to valgrind log. */ /* The first two pass the va_list argument by value, which assumes it is the same size as or smaller than a UWord, which generally isn't the case. Hence are deprecated. The second two pass the vargs by reference and so are immune to this problem. */ /* both :: char* fmt, va_list vargs (DEPRECATED) */ VG_USERREQ__PRINTF = 0x1401, VG_USERREQ__PRINTF_BACKTRACE = 0x1402, /* both :: char* fmt, va_list* vargs */ VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, /* Stack support. */ VG_USERREQ__STACK_REGISTER = 0x1501, VG_USERREQ__STACK_DEREGISTER = 0x1502, VG_USERREQ__STACK_CHANGE = 0x1503, /* Wine support */ VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601, /* Querying of debug info. */ VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701, /* Disable/enable error reporting level. Takes a single Word arg which is the delta to this thread's error disablement indicator. Hence 1 disables or further disables errors, and -1 moves back towards enablement. Other values are not allowed. */ VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801, /* Initialise IR injection */ VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901 } Vg_ClientRequest; #if !defined(__GNUC__) # define __extension__ /* */ #endif /* Returns the number of Valgrinds this code is running under. That is, 0 if running natively, 1 if running under Valgrind, 2 if running under Valgrind which is running under another Valgrind, etc. */ #define RUNNING_ON_VALGRIND \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \ VG_USERREQ__RUNNING_ON_VALGRIND, \ 0, 0, 0, 0, 0) \ /* Discard translation of code in the range [_qzz_addr .. _qzz_addr + _qzz_len - 1]. Useful if you are debugging a JITter or some such, since it provides a way to make sure valgrind will retranslate the invalidated area. Returns no value. */ #define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \ _qzz_addr, _qzz_len, 0, 0, 0) /* These requests are for getting Valgrind itself to print something. Possibly with a backtrace. This is a really ugly hack. The return value is the number of characters printed, excluding the "**** " part at the start and the backtrace (if present). */ #if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) /* Modern GCC will optimize the static routine out if unused, and unused attribute will shut down warnings about it. */ static int VALGRIND_PRINTF(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); #endif static int #if defined(_MSC_VER) __inline #endif VALGRIND_PRINTF(const char *format, ...) { #if defined(NVALGRIND) return 0; #else /* NVALGRIND */ #if defined(_MSC_VER) || defined(__MINGW64__) uintptr_t _qzz_res; #else unsigned long _qzz_res; #endif va_list vargs; va_start(vargs, format); #if defined(_MSC_VER) || defined(__MINGW64__) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_VALIST_BY_REF, (uintptr_t)format, (uintptr_t)&vargs, 0, 0, 0); #else _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_VALIST_BY_REF, (unsigned long)format, (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); return (int)_qzz_res; #endif /* NVALGRIND */ } #if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); #endif static int #if defined(_MSC_VER) __inline #endif VALGRIND_PRINTF_BACKTRACE(const char *format, ...) { #if defined(NVALGRIND) return 0; #else /* NVALGRIND */ #if defined(_MSC_VER) || defined(__MINGW64__) uintptr_t _qzz_res; #else unsigned long _qzz_res; #endif va_list vargs; va_start(vargs, format); #if defined(_MSC_VER) || defined(__MINGW64__) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, (uintptr_t)format, (uintptr_t)&vargs, 0, 0, 0); #else _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, (unsigned long)format, (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); return (int)_qzz_res; #endif /* NVALGRIND */ } /* These requests allow control to move from the simulated CPU to the real CPU, calling an arbitrary function. Note that the current ThreadId is inserted as the first argument. So this call: VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) requires f to have this signature: Word f(Word tid, Word arg1, Word arg2) where "Word" is a word-sized type. Note that these client requests are not entirely reliable. For example, if you call a function with them that subsequently calls printf(), there's a high chance Valgrind will crash. Generally, your prospects of these working are made higher if the called function does not refer to any global variables, and does not refer to any libc or other functions (printf et al). Any kind of entanglement with libc or dynamic linking is likely to have a bad outcome, for tricky reasons which we've grappled with a lot in the past. */ #define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL0, \ _qyy_fn, \ 0, 0, 0, 0) #define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL1, \ _qyy_fn, \ _qyy_arg1, 0, 0, 0) #define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL2, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, 0, 0) #define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL3, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, \ _qyy_arg3, 0) /* Counts the number of errors that have been recorded by a tool. Nb: the tool must record the errors with VG_(maybe_record_error)() or VG_(unique_error)() for them to be counted. */ #define VALGRIND_COUNT_ERRORS \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \ 0 /* default return */, \ VG_USERREQ__COUNT_ERRORS, \ 0, 0, 0, 0, 0) /* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing when heap blocks are allocated in order to give accurate results. This happens automatically for the standard allocator functions such as malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, delete[], etc. But if your program uses a custom allocator, this doesn't automatically happen, and Valgrind will not do as well. For example, if you allocate superblocks with mmap() and then allocates chunks of the superblocks, all Valgrind's observations will be at the mmap() level and it won't know that the chunks should be considered separate entities. In Memcheck's case, that means you probably won't get heap block overrun detection (because there won't be redzones marked as unaddressable) and you definitely won't get any leak detection. The following client requests allow a custom allocator to be annotated so that it can be handled accurately by Valgrind. VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated by a malloc()-like function. For Memcheck (an illustrative case), this does two things: - It records that the block has been allocated. This means any addresses within the block mentioned in error messages will be identified as belonging to the block. It also means that if the block isn't freed it will be detected by the leak checker. - It marks the block as being addressable and undefined (if 'is_zeroed' is not set), or addressable and defined (if 'is_zeroed' is set). This controls how accesses to the block by the program are handled. 'addr' is the start of the usable block (ie. after any redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator can apply redzones -- these are blocks of padding at the start and end of each block. Adding redzones is recommended as it makes it much more likely Valgrind will spot block overruns. `is_zeroed' indicates if the memory is zeroed (or filled with another predictable value), as is the case for calloc(). VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a heap block -- that will be used by the client program -- is allocated. It's best to put it at the outermost level of the allocator if possible; for example, if you have a function my_alloc() which calls internal_alloc(), and the client request is put inside internal_alloc(), stack traces relating to the heap block will contain entries for both my_alloc() and internal_alloc(), which is probably not what you want. For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out custom blocks from within a heap block, B, that has been allocated with malloc/calloc/new/etc, then block B will be *ignored* during leak-checking -- the custom blocks will take precedence. VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For Memcheck, it does two things: - It records that the block has been deallocated. This assumes that the block was annotated as having been allocated via VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - It marks the block as being unaddressable. VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a heap block is deallocated. VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For Memcheck, it does four things: - It records that the size of a block has been changed. This assumes that the block was annotated as having been allocated via VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - If the block shrunk, it marks the freed memory as being unaddressable. - If the block grew, it marks the new area as undefined and defines a red zone past the end of the new block. - The V-bits of the overlap between the old and the new block are preserved. VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block and before deallocation of the old block. In many cases, these three client requests will not be enough to get your allocator working well with Memcheck. More specifically, if your allocator writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call will be necessary to mark the memory as addressable just before the zeroing occurs, otherwise you'll get a lot of invalid write errors. For example, you'll need to do this if your allocator recycles freed blocks, but it zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). Alternatively, if your allocator reuses freed blocks for allocator-internal data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. Really, what's happening is a blurring of the lines between the client program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the memory should be considered unaddressable to the client program, but the allocator knows more than the rest of the client program and so may be able to safely access it. Extra client requests are necessary for Valgrind to understand the distinction between the allocator and the rest of the program. Ignored if addr == 0. */ #define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \ addr, sizeB, rzB, is_zeroed, 0) /* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. Ignored if addr == 0. */ #define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \ addr, oldSizeB, newSizeB, rzB, 0) /* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. Ignored if addr == 0. */ #define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \ addr, rzB, 0, 0, 0) /* Create a memory pool. */ #define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ pool, rzB, is_zeroed, 0, 0) /* Destroy a memory pool. */ #define VALGRIND_DESTROY_MEMPOOL(pool) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \ pool, 0, 0, 0, 0) /* Associate a piece of memory with a memory pool. */ #define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \ pool, addr, size, 0, 0) /* Disassociate a piece of memory from a memory pool. */ #define VALGRIND_MEMPOOL_FREE(pool, addr) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \ pool, addr, 0, 0, 0) /* Disassociate any pieces outside a particular range. */ #define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \ pool, addr, size, 0, 0) /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \ poolA, poolB, 0, 0, 0) /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \ pool, addrA, addrB, size, 0) /* Return 1 if a mempool exists, else 0. */ #define VALGRIND_MEMPOOL_EXISTS(pool) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__MEMPOOL_EXISTS, \ pool, 0, 0, 0, 0) /* Mark a piece of memory as being a stack. Returns a stack id. start is the lowest addressable stack byte, end is the highest addressable stack byte. */ #define VALGRIND_STACK_REGISTER(start, end) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__STACK_REGISTER, \ start, end, 0, 0, 0) /* Unmark the piece of memory associated with a stack id as being a stack. */ #define VALGRIND_STACK_DEREGISTER(id) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \ id, 0, 0, 0, 0) /* Change the start and end address of the stack id. start is the new lowest addressable stack byte, end is the new highest addressable stack byte. */ #define VALGRIND_STACK_CHANGE(id, start, end) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \ id, start, end, 0, 0) /* Load PDB debug info for Wine PE image_map. */ #define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \ fd, ptr, total_size, delta, 0) /* Map a code address to a source file name and line number. buf64 must point to a 64-byte buffer in the caller's address space. The result will be dumped in there and is guaranteed to be zero terminated. If no info is found, the first byte is set to zero. */ #define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__MAP_IP_TO_SRCLOC, \ addr, buf64, 0, 0, 0) /* Disable error reporting for this thread. Behaves in a stack like way, so you can safely call this multiple times provided that VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times to re-enable reporting. The first call of this macro disables reporting. Subsequent calls have no effect except to increase the number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable reporting. Child threads do not inherit this setting from their parents -- they are always created with reporting enabled. */ #define VALGRIND_DISABLE_ERROR_REPORTING \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ 1, 0, 0, 0, 0) /* Re-enable error reporting, as per comments on VALGRIND_DISABLE_ERROR_REPORTING. */ #define VALGRIND_ENABLE_ERROR_REPORTING \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ -1, 0, 0, 0, 0) /* Execute a monitor command from the client program. If a connection is opened with GDB, the output will be sent according to the output mode set for vgdb. If no connection is opened, output will go to the log output. Returns 1 if command not recognised, 0 otherwise. */ #define VALGRIND_MONITOR_COMMAND(command) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__GDB_MONITOR_COMMAND, \ command, 0, 0, 0, 0) #undef PLAT_x86_darwin #undef PLAT_amd64_darwin #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64be_linux #undef PLAT_ppc64le_linux #undef PLAT_arm_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux #undef PLAT_tilegx_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris #endif /* __VALGRIND_H */ 0707010000000F000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000001600000000libsecret-0.21.7/docs07070100000010000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000001A00000000libsecret-0.21.7/docs/man07070100000011000081A400000000000000000000000167D9F0D900000294000000000000000000000000000000000000002600000000libsecret-0.21.7/docs/man/meson.buildsecret_tool_man = custom_target('secret-tool.1', input: 'secret-tool.xml', output: 'secret-tool.1', command: [ find_program('xsltproc'), '-o', '@OUTPUT@', '--nonet', '--stringparam', 'man.output.quietly', '1', '--stringparam', 'man.funcsynopsis.style', 'ansi', '--stringparam', 'man.th.extra1.suppress', '1', '--stringparam', 'man.authors.section.enabled', '0', '--stringparam', 'man.copyright.section.enabled', '0', 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl', '@INPUT@', ], build_by_default: true, install: true, install_dir: libsecret_prefix / get_option('mandir') / 'man1', ) 07070100000012000081A400000000000000000000000167D9F0D9000015B0000000000000000000000000000000000000002A00000000libsecret-0.21.7/docs/man/secret-tool.xml secret-tool XDG Maintainer Stef Walter stefw@gnome.org secret-tool 1 User Commands secret-tool Store and retrieve passwords secret-tool store --label='Label' attribute value ... secret-tool lookup attribute value ... secret-tool clear attribute value ... secret-tool search --allattribute value ... Description secret-tool is a command line tool that can be used to store and retrieve passwords. Each password is stored in an item. Items are uniquely identified by a set of attribute keys and values. When storing a password you must specify unique pairs of attributes names and values, and when looking up a password you provide the same attribute name and value pairs. Store To store a password run secret-tool with the store argument. You must also specify a label for the password with the --label argument. This label will be displayed in the password manager. Make sure to pass a unique set of attributes names and values when storing a password. If the attributes match an already existing item, it will be updated instead of creating a new item. If invoked from a terminal or tty, then the password to store will be prompted for and only one line will be accepted. A password to store can also be piped in via stdin. The password will be the contents of stdin until EOF. If you provide a newline via stdin it will be stored as part of the password. Lookup To lookup a password run secret-tool with the lookup argument. Specify the same same attribute names and value pairs that you passed when storing the password. If multiple items match the attribute provided, then the first password that is already unlocked will be returned. If necessary an item will be unlocked. When printing the password to a terminal or tty, an extra newline will be added after the password. Clear To remove a password run secret-tool with the clear argument. Specify the same attribute name and value pairs that you passed when storing the password. All unlocked items that match the attributes will be removed. Search This command searches for and prints details on matching items in secret service. Specify the same attribute and value pairs that you passed in when storing the password. You can use the following options: Return all matching results, rather than just the one of the matches. Without this option, the first unlocked match returned from the service will be printed. Unlock items that are locked and then print out their details. Without this option, locked items are skipped. Exit status On success 0 is returned, a non-zero failure code otherwise. Examples Storing, retrieving, and clearing a password $ secret-tool store --label='My password' key1 value1 key2 value2 Password: hunter2 $ secret-tool lookup key1 value1 key2 value2 hunter2 $ secret-tool clear key1 value1 key2 value2 Bugs The bug tracker can be reached by visiting the website https://gitlab.gnome.org/GNOME/libsecret/issues. Before sending a bug report, please verify that you have the latest version of secret-tool. Many bugs (major and minor) are fixed at each release, and if yours is out of date, the problem may already have been solved. 07070100000013000081A400000000000000000000000167D9F0D90000006E000000000000000000000000000000000000002200000000libsecret-0.21.7/docs/meson.buildif get_option('manpage') subdir('man') endif if get_option('gtk_doc') subdir('reference/libsecret') endif 07070100000014000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000002000000000libsecret-0.21.7/docs/reference07070100000015000081A400000000000000000000000167D9F0D9000006A1000000000000000000000000000000000000002800000000libsecret-0.21.7/docs/reference/COPYINGThis work may be reproduced and distributed in whole or in part, in any medium, physical or electronic, so as long as this copyright notice remains intact and unchanged on all copies. Commercial redistribution is permitted and encouraged, but you may not redistribute, in whole or in part, under terms more restrictive than those under which you received it. If you redistribute a modified or translated version of this work, you must also make the source code to the modified or translated version available in electronic form without charge. However, mere aggregation as part of a larger work shall not count as a modification for this purpose. All code examples in this work are placed into the public domain, and may be used, modified and redistributed without restriction. BECAUSE THIS WORK IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE WORK, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE WORK "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. SHOULD THE WORK PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY REPAIR OR CORRECTION. 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 WORK 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 WORK, EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 07070100000016000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000002A00000000libsecret-0.21.7/docs/reference/libsecret07070100000017000081A400000000000000000000000167D9F0D900001C5F000000000000000000000000000000000000004200000000libsecret-0.21.7/docs/reference/libsecret/libsecret-c-examples.mdTitle: C Examples Slug: libsecret-c-example # C Examples ## Define a password schema Each stored password has a set of attributes which are later used to lookup the password. The names and types of the attributes are defined in a schema. The schema is usually defined once globally. Here's how to define a schema: ```c // in a header: const SecretSchema * example_get_schema (void) G_GNUC_CONST; #define EXAMPLE_SCHEMA example_get_schema () // in a .c file: const SecretSchema * example_get_schema (void) { static const SecretSchema the_schema = { "org.example.Password", SECRET_SCHEMA_NONE, { { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, { "NULL", 0 }, } }; return &the_schema; } ``` See the [other examples](#store-a-password) for how to use the schema. ## Store a password Here's how to store a password in the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are later used to lookup the password. The attributes should not contain secrets, as they are not stored in an encrypted fashion. These examples use the [example schema](#define-a-password-schema). This first example stores a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```c static void on_password_stored (GObject *source, GAsyncResult *result, gpointer unused) { GError *error = NULL; secret_password_store_finish (result, &error); if (error != NULL) { /* ... handle the failure here */ g_error_free (error); } else { /* ... do something now that the password has been stored */ } } /* * The variable argument list is the attributes used to later * lookup the password. These attributes must conform to the schema. */ secret_password_store (EXAMPLE_SCHEMA, SECRET_COLLECTION_DEFAULT, "The label", "the password", NULL, on_password_stored, NULL, "number", 8, "string", "eight", "even", TRUE, NULL); ``` This next example stores a password synchronously. The function call will block until the password is stored. So this is appropriate for non GUI applications. ```c GError *error = NULL; /* * The variable argument list is the attributes used to later * lookup the password. These attributes must conform to the schema. */ secret_password_store_sync (EXAMPLE_SCHEMA, SECRET_COLLECTION_DEFAULT, "The label", "the password", NULL, &error, "number", 9, "string", "nine", "even", FALSE, NULL); if (error != NULL) { /* ... handle the failure here */ g_error_free (error); } else { /* ... do something now that the password has been stored */ } ``` ## Lookup a password Here's how to lookup a password in the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are used to lookup the password. If multiple passwords match the lookup attributes, then the one stored most recently is returned. These examples use the [example schema](#define-a-password-schema). This first example looks up a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```c static void on_password_lookup (GObject *source, GAsyncResult *result, gpointer unused) { GError *error = NULL; gchar *password = secret_password_lookup_finish (result, &error); if (error != NULL) { /* ... handle the failure here */ g_error_free (error); } else if (password == NULL) { /* password will be null, if no matching password found */ } else { /* ... do something with the password */ secret_password_free (password); } } /* * The variable argument list is the attributes used to later * lookup the password. These attributes must conform to the schema. */ secret_password_lookup (EXAMPLE_SCHEMA, NULL, on_password_lookup, NULL, "string", "nine", "even", FALSE, NULL); ``` This next example looks up a password synchronously. The function call will block until the lookup completes. So this is appropriate for non GUI applications. ```c GError *error = NULL; /* The attributes used to lookup the password should conform to the schema. */ gchar *password = secret_password_lookup_sync (EXAMPLE_SCHEMA, NULL, &error, "string", "nine", "even", FALSE, NULL); if (error != NULL) { /* ... handle the failure here */ g_error_free (error); } else if (password == NULL) { /* password will be null, if no matching password found */ } else { /* ... do something with the password */ secret_password_free (password); } ``` ## Remove a password Here's how to remove a password from the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are used to find which password to remove. If multiple passwords match the attributes, then the one stored most recently is removed. These examples use the [example schema](#define-a-password-schema). This first example removes a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```c static void on_password_cleared (GObject *source, GAsyncResult *result, gpointer unused) { GError *error = NULL; gboolean removed = secret_password_clear_finish (result, &error); if (error != NULL) { /* ... handle the failure here */ g_error_free (error); } else { /* removed will be TRUE if a password was removed */ } } /* * The variable argument list is the attributes used to later * lookup the password. These attributes must conform to the schema. */ secret_password_clear (EXAMPLE_SCHEMA, NULL, on_password_cleared, NULL, "string", "nine", "even", FALSE, NULL); ``` This next example looks up a password synchronously. The function call will block until the lookup completes. So this is appropriate for non GUI applications. ```c GError *error = NULL; /* * The variable argument list is the attributes used to later * lookup the password. These attributes must conform to the schema. */ gboolean removed = secret_password_clear_sync (EXAMPLE_SCHEMA, NULL, &error, "string", "nine", "even", FALSE, NULL); if (error != NULL) { /* ... handle the failure here */ g_error_free (error); } else { /* removed will be TRUE if a password was removed */ } ``` 07070100000018000081A400000000000000000000000167D9F0D9000014A7000000000000000000000000000000000000004300000000libsecret-0.21.7/docs/reference/libsecret/libsecret-js-examples.mdTitle: Javascript Examples Slug: libsecret-js-example # Javascript examples ## Define a password schema Each stored password has a set of attributes which are later used to lookup the password. The names and types of the attributes are defined in a schema. The schema is usually defined once globally. Here's how to define a schema: ```js const Secret = imports.gi.Secret; /* This schema is usually defined once globally */ const EXAMPLE_SCHEMA = new Secret.Schema.new("org.example.Password", Secret.SchemaFlags.NONE, { "number": Secret.SchemaAttributeType.INTEGER, "string": Secret.SchemaAttributeType.STRING, "even": Secret.SchemaAttributeType.BOOLEAN, } ); ``` See the [other examples](#store-a-password) for how to use the schema. ## Store a password Here's how to store a password in the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are later used to lookup the password. The attributes should not contain secrets, as they are not stored in an encrypted fashion. These examples use the [example schema](#define-a-password-schema). This first example stores a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```js const Secret = imports.gi.Secret; function on_password_stored(source, result) { Secret.password_store_finish(result); /* ... do something now that the password has been stored */ } /* * The attributes used to later lookup the password. These * attributes should conform to the schema. */ var attributes = { "number": "8", "string": "eight", "even": "true" }; Secret.password_store(EXAMPLE_SCHEMA, attributes, Secret.COLLECTION_DEFAULT, "The label", "the password", null, on_password_stored); ``` This next example stores a password synchronously. The function call will block until the password is stored. So this is appropriate for non GUI applications. ```js const Secret = imports.gi.Secret; /* * The attributes used to later lookup the password. These * attributes should conform to the schema. */ var attributes = { "number": "9", "string": "nine", "even": "false" }; Secret.password_store_sync(EXAMPLE_SCHEMA, attributes, Secret.COLLECTION_DEFAULT, "The label", "the password", null); ``` ## Lookup a password Here's how to lookup a password in the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are used to lookup the password. If multiple passwords match the lookup attributes, then the one stored most recently is returned. These examples use the [example schema](#define-a-password-schema). This first example looks up a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```js const Secret = imports.gi.Secret; function on_password_lookup(source, result) { var password = Secret.password_lookup_finish(result); /* password will be null if no matching password found */ } /* The attributes used to lookup the password should conform to the schema. */ Secret.password_lookup(EXAMPLE_SCHEMA, { "number": "8", "even": "true" }, null, on_password_lookup); ``` This next example looks up a password synchronously. The function call will block until the lookup completes. So this is appropriate for non GUI applications. ```js const Secret = imports.gi.Secret; /* The attributes used to lookup the password should conform to the schema. */ var password = Secret.password_lookup_sync(EXAMPLE_SCHEMA, { "number": "8", "even": "true" }, null); /* password will be null, if no matching password found */ ``` ## Remove a password Here's how to remove a password from the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are used to find which password to remove. If multiple passwords match the attributes, then the one stored most recently is removed. These examples use the [example schema](#define-a-password-schema). This first example removes a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```js const Secret = imports.gi.Secret; function on_password_clear(source, result) { var removed = Secret.password_clear_finish(result); /* removed will be true if the password was removed */ } /* The attributes used to lookup which password to remove should conform to the schema. */ Secret.password_clear(EXAMPLE_SCHEMA, { "number": "8", "even": "true" }, null, on_password_clear); ``` This next example removes a password synchronously. The function call will block until the removal completes. So this is appropriate for non GUI applications. ```js const Secret = imports.gi.Secret; /* The attributes used to lookup which password to remove should conform to the schema. */ var removed = Secret.password_clear_sync(EXAMPLE_SCHEMA, { "number": "8", "even": "true" }, null); /* removed will be true if the password was removed */ ``` 07070100000019000081A400000000000000000000000167D9F0D900001232000000000000000000000000000000000000004700000000libsecret-0.21.7/docs/reference/libsecret/libsecret-python-examples.mdTitle: Python Examples Slug: libsecret-python-example # Python examples ## Define a password schema Each stored password has a set of attributes which are later used to lookup the password. The names and types of the attributes are defined in a schema. The schema is usually defined once globally. Here's how to define a schema: ```python from gi.repository import Secret EXAMPLE_SCHEMA = Secret.Schema.new("org.mock.type.Store", Secret.SchemaFlags.NONE, { "number": Secret.SchemaAttributeType.INTEGER, "string": Secret.SchemaAttributeType.STRING, "even": Secret.SchemaAttributeType.BOOLEAN, } ) ``` See the [other examples](#store-a-password) for how to use the schema. ## Store a password Here's how to store a password in the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are later used to lookup the password. The attributes should not contain secrets, as they are not stored in an encrypted fashion. These examples use the [example schema](#define-a-password-schema). This first example stores a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```python from gi.repository import Secret def on_password_stored(source, result, unused): Secret.password_store_finish(result) # ... do something now that the password has been stored # The attributes used to later lookup the password. These # attributes should conform to the schema. attributes = { "number": "8", "string": "eight", "even": "true" } Secret.password_store(EXAMPLE_SCHEMA, attributes, Secret.COLLECTION_DEFAULT, "The label", "the password", None, on_password_stored) ``` This next example stores a password synchronously. The function call will block until the password is stored. So this is appropriate for non GUI applications. ```python from gi.repository import Secret # The attributes used to later lookup the password. These # attributes should conform to the schema. attributes = { "number": "8", "string": "eight", "even": "true" } Secret.password_store_sync(EXAMPLE_SCHEMA, attributes, Secret.COLLECTION_DEFAULT, "The label", "the password", None) ``` ## Lookup a password Here's how to lookup a password in the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are used to lookup the password. If multiple passwords match the lookup attributes, then the one stored most recently is returned. These examples use the [example schema](#define-a-password-schema). This first example looks up a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```python from gi.repository import Secret def on_password_lookup(source, result, unused): password = Secret.password_lookup_finish(result) # password will be null, if no matching password found Secret.password_lookup(EXAMPLE_SCHEMA, { "number": "8", "even": "true" }, None, on_password_lookup) ``` This next example looks up a password synchronously. The function call will block until the lookup completes. So this is appropriate for non GUI applications. ```python from gi.repository import Secret password = Secret.password_lookup_sync(EXAMPLE_SCHEMA, { "number": "8", "even": "true" }, None) # password will be null, if no matching password found ``` ## Remove a password Here's how to remove a password from the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are used to find which password to remove. If multiple passwords match the attributes, then the one stored most recently is removed. These examples use the [example schema](#define-a-password-schema). This first example removes a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```python from gi.repository import Secret def on_password_clear(source, result, unused): removed = Secret.password_clear_finish(result) # removed will be true if the password was removed Secret.password_clear(EXAMPLE_SCHEMA, { "number": "8", "even": "true" }, None, on_password_clear) ``` This next example removes a password synchronously. The function call will block until the removal completes. So this is appropriate for non GUI applications. ```python from gi.repository import Secret removed = Secret.password_clear_sync(EXAMPLE_SCHEMA, { "number": "8", "even": "true" }, None) # removed will be true if the password was removed ``` 0707010000001A000081A400000000000000000000000167D9F0D900000598000000000000000000000000000000000000004200000000libsecret-0.21.7/docs/reference/libsecret/libsecret-simple-api.mdTitle: Simple API Slug: libsecret-simple-api # Simple API ## SecretPassword Simple password storage and lookup. This is a simple API for storing passwords and retrieving passwords in the Secret Service. Each password is associated with a set of attributes. Attribute values can be either strings, integers or booleans. The names and types of allowed attributes for a given password are defined with a schema. Certain schemas are predefined. Additional schemas can be defined via the [struct@Schema] structure. Each of the functions accept a variable list of attributes names and their values. Include a `NULL` to terminate the list of attributes. ## Secret Attributes Each item has a set of attributes, which are used to locate the item later. These are not stored or transferred in a secure manner. Each attribute has a string name and a string value. These attributes are represented by a [struct@GLib.HashTable] with string keys and values. Use [func@attributes_build] to simply build up a set of attributes. ## DBus Path Related Functions Secret Service functions which operate on DBus object paths These are low level functions which operate on DBus object paths of collections or items, instead of the [class@Collection] or [class@Item] objects themselves. You can use these functions if you wish to manage access to the secret service using the DBus API directly, and only wish to use a few calls in libsecret. 0707010000001B000081A400000000000000000000000167D9F0D900000A20000000000000000000000000000000000000003C00000000libsecret-0.21.7/docs/reference/libsecret/libsecret-tpm2.mdTitle: Extending file backend to use a TPM Slug: libsecret-tpm2 # Extending file backend to use a TPM ## Introduction The current implementation of file backend uses an encryption key derived from the user's login password. Security wise this not an ideal situation. Because, the entire security of the file backend relies on the user's login password (single point of failure). This situation can be improved if the keys are protected/generated by hardware. A Trusted Platform Module (TPM) is a such hardware security module found in modern computer systems. The new `EGG_TPM2` API based on the "TSS Enhanced System API (ESAPI)" ```c EggTpm2Context *egg_tpm2_initialize (GError **); void egg_tpm2_finalize (EggTpm2Context *); GBytes *egg_tpm2_generate_master_password (EggTpm2Context *, GError **); GBytes *egg_tpm2_decrypt_master_password (EggTpm2Context *, GBytes *, GError **); ``` ## Build and test libsecret with TPM2 support In order to try out the `TPM2 support` use the `-Dtpm2=true` build option/flag during the `meson _build` process. You can alter the default build and install process as the following: ```sh meson _build -Dtpm2=true ninja -C _build ninja -C _build install ``` For testing the TPM2 support you need a physical TPM or a TPM emulator. The following sections demonstrate how to setup [swtpm](https://github.com/stefanberger/swtpm) emulator and testing out the TPM2 support. If you have access to a TPM you can ignore the emulator section. swtpm emulator setup: ```sh dnf install swtpm swtpm-tools tpm2-abrmd tpm2-tss-devel eval `dbus-launch --sh-syntax` export XDG_CONFIG_HOME=$HOME/.config/swtpm /usr/share/swtpm/swtpm-create-user-config-files --root mkdir -p ${XDG_CONFIG_HOME}/mytpm1 swtpm_setup --tpm2 --tpmstate $XDG_CONFIG_HOME/mytpm1 --createek --allow-signing --decryption --create-ek-cert --create-platform-cert --lock-nvram --overwrite --display swtpm socket --tpm2 --tpmstate dir=$XDG_CONFIG_HOME/mytpm1 --flags startup-clear --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --daemon tpm2-abrmd --logger=stdout --tcti=swtpm: --session --allow-root --flush-all & export TCTI=tabrmd:bus_type=session ``` Test TPM2 support: ```sh cd libsecret meson _build -Dtpm2=true ninja -C _build export SECRET_BACKEND=file export SECRET_FILE_TEST_PATH=$PWD/keyring ./_build/tool/secret-tool store --label=foo bar baz ls # keyring ``` 0707010000001C000081A400000000000000000000000167D9F0D90000081E000000000000000000000000000000000000003D00000000libsecret-0.21.7/docs/reference/libsecret/libsecret-using.mdTitle: Using libsecret Slug: libsecret-using # Using libsecret in builds or scripts ## C: Compiling with libsecret Like other GNOME libraries, libsecret uses `pkg-config` to provide compiler options. The package name is `libsecret-1`. So in your `configure.ac` script,you might specify something like: ``` PKG_CHECK_MODULES(LIBSECRET, [libsecret-1 >= 1.0]) AC_SUBST(LIBSECRET_CFLAGS) AC_SUBST(LIBSECRET_LIBS) ``` Code using libsecret should include the header like this: ```c #include ``` Including individual headers besides the main header files is not permitted and will cause an error. Some parts of the libsecret API are not yet stable. To use them you need use the `libsecret-unstable` package. The API contained in this package will change from time to time. Here's how you would do it: ``` PKG_CHECK_MODULES(LIBSECRET, [libsecret-unstable >= 1.0]) AC_SUBST(LIBSECRET_CFLAGS) AC_SUBST(LIBSECRET_LIBS) ``` ## Javascript: Importing libsecret In Javascript use the standard introspection import mechanism to get at libsecret: ```js const Secret = imports.gi.Secret; // ... and here's a sample line of code which uses the import var schema = new Secret.Schema.new("org.mock.Schema", Secret.SchemaFlags.NONE, { "name", Secret.SchemaAttributeType.STRING }); ``` ## Python: Importing libsecret In python use the standard introspection import mechanism to get at libsecret: ```python import gi gi.require_version("Secret", "1") from gi.repository import Secret # ... and a here's sample line of code which uses the import schema = Secret.Schema.new("org.mock.Schema", Secret.SchemaFlags.NONE, { "name": Secret.SchemaAttributeType.STRING }) ``` ## Vala: Compiling with libsecret The package name is `libsecret-1`. You can use it like this in your `Makefile.am` file: ``` AM_VALAFLAGS = \ --pkg=libsecret-1 ``` Some parts of the libsecret API are not yet stable. To use them you need to define the `SECRET_WITH_UNSTABLE` C preprocessor macro to use them, or else the build will fail: ``` AM_CPPFLAGS = \ -DSECRET_WITH_UNSTABLE=1 ``` 0707010000001D000081A400000000000000000000000167D9F0D900001553000000000000000000000000000000000000004500000000libsecret-0.21.7/docs/reference/libsecret/libsecret-vala-examples.mdTitle: Vala Examples Slug: libsecret-vala-example # Vala Examples ## Define a password schema Each stored password has a set of attributes which are later used to lookup the password. The names and types of the attributes are defined in a schema. The schema is usually defined once globally. Here's how to define a schema: ```vala var example = new Secret.Schema ("org.example.Password", Secret.SchemaFlags.NONE, "number", Secret.SchemaAttributeType.INTEGER, "string", Secret.SchemaAttributeType.STRING, "even", Secret.SchemaAttributeType.BOOLEAN); ``` See the [other examples](#store-a-password) for how to use the schema. ## Store a password Here's how to store a password in the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are later used to lookup the password. The attributes should not contain secrets, as they are not stored in an encrypted fashion. These examples use the [example schema](#define-a-password-schema). This first example stores a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```vala var attributes = new GLib.HashTable (); attributes["number"] = "8"; attributes["string"] = "eight"; attributes["even"] = "true"; Secret.password_storev.begin (example_schema, attributes, Secret.COLLECTION_DEFAULT, "The label", "the password", null, (obj, async_res) => { bool res = Secret.password_store.end (async_res); /* ... do something now that the password has been stored */ }); ``` If you are already inside of an async function, you can also use the yield keyword: ```vala var attributes = new GLib.HashTable (); attributes["number"] = "8"; attributes["string"] = "eight"; attributes["even"] = "true"; bool res = yield Secret.password_storev (example_schema, attributes, Secret.COLLECTION_DEFAULT, "The label", "the password", null); ``` If you would like to avoid creating a hash table for the attributes you can just use the variadic version: ```vala bool res = yield Secret.password_store (example_schema, Secret.COLLECTION_DEFAULT, "The label", "the password", null, "number", 8, "string", "eight", "even", true); ``` This next example stores a password synchronously. The function call will block until the password is stored. So this is appropriate for non GUI applications. ```vala Secret.password_store_sync (example_schema, attributes, Secret.COLLECTION_DEFAULT, "The label", "the password", null, "number", 9, "string", "nine", "even", false); ``` ## Lookup a password Here's how to lookup a password in the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are used to lookup the password. If multiple passwords match the lookup attributes, then the one stored most recently is returned. These examples use the [example schema](#define-a-password-schema). This first example looks up a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```vala var attributes = new GLib.HashTable (); attributes["number"] = "8"; attributes["string"] = "eight"; attributes["even"] = "true"; Secret.password_lookupv.begin (example_schema, attributes, null, (obj, async_res) => { string password = Secret.password_lookup.end (async_res); }); ``` This next example looks up a password synchronously. The function call will block until the lookup completes. So this is appropriate for non GUI applications. ```vala string password = Secret.password_lookup_sync (example_schema, attributes, null, "number", 9, "string", "nine", "even", false); /* password will be null, if no matching password found */ ``` ## Remove a password Here's how to remove a password from the running secret service, like gnome-keyring or ksecretservice. Each stored password has a set of attributes which are used to find which password to remove. If multiple passwords match the attributes, then the one stored most recently is removed. These examples use the [example schema](#define-a-password-schema). This first example removes a password asynchronously, and is appropriate for GUI applications so that the UI does not block. ```vala var attributes = new GLib.HashTable (); attributes["number"] = "8"; attributes["string"] = "eight"; attributes["even"] = "true"; Secret.password_clearv.begin (example_schema, attributes, null, (obj, async_res) => { bool removed = Secret.password_clearv.end (async_res); }); ``` This next example removes a password synchronously. The function call will block until the removal completes. So this is appropriate for non GUI applications. ```vala var attributes = new GLib.HashTable (); attributes["number"] = "8"; attributes["string"] = "eight"; attributes["even"] = "true"; bool removed = Secret.password_clear_sync (example_schema, null, "number", 8, "string", "eight", "even", true); /* removed will be true if the password was removed */ ``` 0707010000001E000081A400000000000000000000000167D9F0D9000005AD000000000000000000000000000000000000003C00000000libsecret-0.21.7/docs/reference/libsecret/libsecret.toml.in[library] version = "@VERSION@" browse_url = "https://gitlab.gnome.org/GNOME/libsecret" repository_url = "https://gitlab.gnome.org/GNOME/libsecret.git" docs_url = "https://gnome.pages.gitlab.gnome.org/libsecret/" website_url = "https://gnome.pages.gitlab.gnome.org/libsecret/" authors = "Stef Walter, Daiki Ueno, and Niels De Graef" license = "LGPL-2.1-or-later" description = "Secret Service D-Bus client library" dependencies = [ "GObject-2.0", "GLib-1.0", "Gio-2.0" ] devhelp = true search_index = true [dependencies."GObject-2.0"] name = "GObject" description = "The base type system library" docs_url = "https://docs.gtk.org/gobject/" [dependencies."GLib-2.0"] name = "GLib" description = "The base type system library" docs_url = "https://docs.gtk.org/glib/" [dependencies."Gio-2.0"] name = "GIO" description = "GObject Interfaces and Objects, Networking, IPC, and I/O" docs_url = "https://docs.gtk.org/gio/" [theme] name = "basic" show_index_summary = true show_class_hierarchy = true [source-location] base_url = "https://gitlab.gnome.org/GNOME/libsecret/-/blob/master/" [extra] # The same order will be used when generating the index content_files = [ 'libsecret-using.md', 'libsecret-simple-api.md', "libsecret-c-examples.md", "libsecret-js-examples.md", "libsecret-python-examples.md", "libsecret-vala-examples.md", "libsecret-tpm2.md", "migrating-libgnome-keyring.md", ] content_images = [ ] urlmap_file = "urlmap.js" 0707010000001F000081A400000000000000000000000167D9F0D9000004F5000000000000000000000000000000000000003600000000libsecret-0.21.7/docs/reference/libsecret/meson.buildexpand_content_md_files = [ 'libsecret-c-examples.md', 'libsecret-js-examples.md', 'libsecret-python-examples.md', 'libsecret-simple-api.md', 'libsecret-tpm2.md', 'libsecret-using.md', 'libsecret-vala-examples.md', 'migrating-libgnome-keyring.md', ] toml_data = configuration_data() toml_data.set('VERSION', meson.project_version()) libsecret_toml = configure_file( input: 'libsecret.toml.in', output: 'libsecret.toml', configuration: toml_data ) dependency('gi-docgen', version: '>= 2021.7', fallback: ['gi-docgen', 'dummy_dep'], native: true, required: get_option('gtk_doc')) gidocgen = find_program('gi-docgen') docs_dir = get_option('datadir') / 'doc' custom_target('libsecret-doc', input: [ libsecret_toml, libsecret_gir[0] ], output: 'libsecret-@0@'.format(api_version_major), command: [ gidocgen, 'generate', '--quiet', '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../libsecret'), '--config=@INPUT0@', '--output-dir=@OUTPUT@', '--no-namespace-dir', '--content-dir=@0@'.format(meson.current_source_dir()), '@INPUT1@', ], depend_files: [ expand_content_md_files ], build_by_default: true, install: true, install_dir: docs_dir, ) 07070100000020000081A400000000000000000000000167D9F0D900007121000000000000000000000000000000000000004800000000libsecret-0.21.7/docs/reference/libsecret/migrating-libgnome-keyring.mdTitle: Migrating from libgnome-keyring Slug: migrating-libgnome-keyring # Migrating from libgnome-keyring ## Introduction Conceptually, libgnome-keyring and libsecret are fairly similar. Both have keyrings, items, and ways to store and retrieve passwords. In both cases items have attributes. The keys and values of attributes are used to lookup a password that was stored. There is a simple password API for storing and retrieving passwords which is the easiest and recommended way to store passwords. And then there is a more complicated API which models all the various collections and items, along with all the possible actions that can be performed on them. libsecret uses the Secret Service DBus API to communicate with gnome-keyring-daemon, and as such exposes features based on that DBus API. libsecret has been designed to be threadsafe, and uses the 'GDBus' code in gio to accomplish this. Keyrings are called 'collections' in libsecret. See the relevant section for specifics about how to port the libgnome-keyring functions or symbols in your project. ## API conversion Here are some clues on how to migrate various libgnome-keyring API functions and their logical equivalents in libsecret. ### Item attributes Remember that attributes are not, and never have been stored in an encrypted fashion. They are not part of the 'secret', but instead are a way to lookup a secret item. All attributes in libsecret are stored as strings. Sets of attributes are represented by [struct@GLib.HashTable]s and the keys and values of these hash tables are strings. libsecret is far more focused on schemas, and encourages users to define a [struct@Schema] for their password storage. The schema defines which attributes are allowed an item. Each schema has a name which is usually a dotted string (eg: `org.gnome.MyProject.Password`). This schema name is stored internally in the item attributes. Schemas define whether an attribute should look like an integer, a boolean, or a free-form string. These types are used when validating the attribute values, even though the attribute values are stored and matched as strings. Since attribute values are used primarily for lookup of items it's important that the string representations of integers and booleans are always identical. Boolean values are stored as the strings `true` and `false`. Integer values are stored in decimal, with a preceding negative sign for negative integers. libsecret facilitates this using the [func@attributes_build] and [func@attributes_buildv] functions. Attributes are meant to be used for lookup of items; they're not designed to be used as a generic key/value database. Although you can force libsecret to do the latter, it's better to store your account information elsewhere if possible, and use libsecret to store the password or other secret. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
GnomeKeyringAttributeList a [struct@GLib.HashTable] of string keys and values
GnomeKeyringAttribute a key/value pair in a [struct@GLib.HashTable] of strings
GnomeKeyringAttributeType [struct@Schema]AttributeType
GNOME_KEYRING_ATTRIBUTE_TYPE_STRING SECRET_SCHEMA_ATTRIBUTE_STRING
GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 SECRET_SCHEMA_ATTRIBUTE_INTEGER
gnome_keyring_attribute_list_index() use [func@GLib.HashTable.lookup] on the attributes hash table
gnome_keyring_attribute_get_string() use [func@GLib.HashTable.lookup] on the attributes hash table
gnome_keyring_attribute_get_uint32() no equivalent, use [func@GLib.HashTable.lookup]
gnome_keyring_attribute_list_append_string() [func@attributes_build]
gnome_keyring_attribute_list_append_uint32() [func@attributes_build]
gnome_keyring_attribute_list_copy() [func@GLib.HashTable.ref]
gnome_keyring_attribute_list_free() [func@GLib.HashTable.unref]
gnome_keyring_attribute_list_index() no equivalent, use [func@GLib.HashTable.lookup]
gnome_keyring_attribute_list_new() [func@attributes_build]
## Working with schemas libsecret is far more focused on schemas, and encourages users to define a [struct@Schema] for their password storage. The schema defines which attributes are allowed an item. Each schema has a name which is usually a dotted string (eg: `org.gnome.MyProject.Password`). This name is stored in the item attributes. The schema name is also used when looking up an item, to make sure that the stored schema matches that used during the lookup. If you wish to lookup items that were stored by libgnome-keyring, you should specify the `SECRET_SCHEMA_DONT_MATCH_NAME` flag in the schema so that the schema name is not matched, since it was not stored by libgnome-keyring. Schemas define whether an attribute should look like an integer, a boolean, or a free-form string. These types are used when validating the attribute values stored, even though the attribute values are stored and matched as strings. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
GnomeKeyringPasswordSchema [struct@Schema]
GnomeKeyringPasswordSchemaAttribute [struct@Schema]Attribute
GNOME_KEYRING_ITEM_APPLICATION_SECRET no equivalent
GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD no equivalent
GNOME_KEYRING_ITEM_ENCRYPTION_KEY_PASSWORD no equivalent
GNOME_KEYRING_ITEM_PK_STORAGE no equivalent
GNOME_KEYRING_ITEM_GENERIC_SECRET no equivalent, define a specific schema with an appropriate dotted name
GNOME_KEYRING_ITEM_NETWORK_PASSWORD the SECRET_SCHEMA_COMPAT_NETWORK schema, although not recommended for new uses
GNOME_KEYRING_ITEM_NOTE the SECRET_SCHEMA_NOTE schema
GNOME_KEYRING_NETWORK_PASSWORD the SECRET_SCHEMA_COMPAT_NETWORK schema, although not recommended for new uses
## Storing passwords and items It's encouraged to use a [struct@Schema] when storing items and passwords. By default most ways of storing an item will now overwrite another item with the same attributes in the same keyring. To manually control this behavior use the [func@Item.create]. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
GNOME_KEYRING_DEFAULT [const@COLLECTION_DEFAULT]
GNOME_KEYRING_SESSION [const@COLLECTION_SESSION]
gnome_keyring_store_password() [func@password_store]
gnome_keyring_store_password_sync() [func@password_store_sync]
gnome_keyring_set_network_password() [func@password_store] with SECRET_SCHEMA_COMPAT_NETWORK although this is not recommended for new uses.
gnome_keyring_set_network_password_sync() [func@password_store_sync] with SECRET_SCHEMA_COMPAT_NETWORK although this is not recommended for new uses.
gnome_keyring_item_create() [func@Item.create], although using [func@password_store] is simpler.
gnome_keyring_item_create_sync() [func@Item.create], although using [func@password_store_sync] is simpler.
## Searching for passwords and items In general libsecret tries not to unlocking keyrings where not necessary. Many search methods only return one item or password that matches, preferring already unlocked items, and recently stored items. Attributes are meant to be used for lookup of items; they're not designed to be used as a generic key/value database. Although you can force libsecret to do the latter, it's better to store your account information elsewhere if possible, and use libsecret to store the password or other secret. Because of this many search methods return just the password or secret. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
gnome_keyring_find_password() [func@password_lookup]
gnome_keyring_find_password_sync() [func@password_lookup_sync]
gnome_keyring_find_items() [method@Service.search], with flags to fine tune behavior
gnome_keyring_find_itemsv() [method@Service.search], with flags to fine tune behavior
gnome_keyring_find_items_sync() [method@Service.search_sync], with flags to fine tune behavior
gnome_keyring_find_itemsv_sync() [method@Service.search], with flags to fine tune behavior
GnomeKeyringFound no equivalent, [method@Service.search] returns a [struct@GLib.List] of [class@Item]s, and other methods return passwords directly.
gnome_keyring_found_copy() no equivalent
gnome_keyring_found_free() [method@GObject.Object.unref] on the each of the items returned from [method@Service.search]
gnome_keyring_found_list_free() [func@GLib.List.free_full] used with [method@GObject.Object.unref] on the items returned from [method@Service.search]
gnome_keyring_find_network_password() [func@password_lookup] with SECRET_SCHEMA_COMPAT_NETWORK, although this only returns one password and no attributes
gnome_keyring_find_network_password_sync() [func@password_lookup_sync] with SECRET_SCHEMA_COMPAT_NETWORK, although this only returns one password and no attributes
GnomeKeyringNetworkPasswordData no equivalent, [func@password_lookup] gets the password directly and no attributes
gnome_keyring_network_password_free() no equivalent
gnome_keyring_network_password_list_free() no equivalent
## Removing passwords and icons Neither libgnome-keyring or libsecret allow deletion of locked items. libsecret tries to make it easier to delete all unlocked items matching certain attributes. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
gnome_keyring_delete_password() [func@password_clear], although we now try to delete all unlocked matching items
gnome_keyring_delete_password_sync() [func@password_clear_sync], although we now try to delete all unlocked matching items
gnome_keyring_item_delete() [method@Item.delete]
gnome_keyring_item_delete_sync() [method@Item.delete_sync]
## Item management In libsecret items are no longer identified by an unsigned integer. Applications should retrieve items based on their attributes. It is also possible to identify an item by its DBus object path. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
gnome_keyring_item_create() [func@Item.create], although [func@password_store] may be simpler
gnome_keyring_item_create_sync() [func@Item.create_sync], although [func@password_store_sync] may be simpler
gnome_keyring_item_delete() [method@Item.delete], although [func@password_clear] may be simpler
gnome_keyring_item_delete_sync() [method@Item.delete_sync], although [func@password_clear_sync] may be simpler
gnome_keyring_item_get_info() properties are loaded on a [class@Item] automatically, use [method@Item.load_secret] to load the secret
gnome_keyring_item_get_info_sync() properties are loaded on a [class@Item] automatically, use [method@Item.load_secret_sync] to load the secret
gnome_keyring_item_get_info_full() properties are loaded on a [class@Item] automatically, use [method@Item.load_secret] to load the secret
gnome_keyring_item_get_info_full_sync() properties are loaded on a [class@Item] automatically, use [method@Item.load_secret_sync] to load the secret
gnome_keyring_item_set_info() use the appropriate setter methods on [class@Item]
gnome_keyring_item_set_info_sync() use the appropriate setter methods on [class@Item]
gnome_keyring_item_get_attributes() [method@Item.get_attributes]
gnome_keyring_item_get_attributes_sync() [method@Item.get_attributes]
gnome_keyring_item_set_attributes() [method@Item.set_attributes]
gnome_keyring_item_set_attributes_sync() [method@Item.set_attributes_sync]
GnomeKeyringItemType replaced by the name of a [struct@Schema]
GnomeKeyringItemInfo [class@Item]
gnome_keyring_item_info_new() no equivalent
gnome_keyring_item_info_copy() no equivalent
gnome_keyring_item_info_free() [method@GObject.Object.unref] on the [class@Item]
gnome_keyring_item_info_get_display_name() [method@Item.get_label]
gnome_keyring_item_info_set_display_name() [method@Item.set_label]
gnome_keyring_item_info_get_ctime() [method@Item.get_created]
gnome_keyring_item_info_get_mtime() [method@Item.get_modified]
gnome_keyring_item_info_get_type() [method@Item.get_schema_name]
gnome_keyring_item_info_set_type() [method@Item.set_attributes] with appropriate schema
gnome_keyring_item_info_get_secret() [method@Item.get_secret]
gnome_keyring_item_info_set_secret() [method@Item.set_secret] and [method@Item.set_secret_sync]
GNOME_KEYRING_ITEM_INFO_BASICS no equivalent, all basic item properties are loaded on [class@Item] automatically
GNOME_KEYRING_ITEM_INFO_SECRET use [method@Item.load_secret] and [method@Item.load_secret_sync] to load the secret for an item.
gnome_keyring_item_info_set_display_name()
## Keyring management In libsecret keyrings are called 'collections'. This is the same lingo as the underlying Secret Service DBus API. Keyrings are no longer identified by simple keyring names. Normally applications just use the default keyrings and these are identified by the aliases [const@COLLECTION_DEFAULT] and [const@COLLECTION_SESSION]. It is also possible to identify collections by their DBus object paths. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
gnome_keyring_create() [func@Collection.create]
gnome_keyring_create_sync() [func@Collection.create_sync]
gnome_keyring_delete() [method@Collection.delete]
gnome_keyring_delete_sync() [method@Collection.delete_sync]
gnome_keyring_change_password() no equivalent, use platform specific DBus APIs
gnome_keyring_change_password_sync() no equivalent, use platform specific DBus APIs
gnome_keyring_list_keyring_names() [method@Service.load_collections] and [method@Service.get_collections]
gnome_keyring_list_keyring_names_sync() [method@Service.load_collections_sync] and [method@Service.get_collections]
gnome_keyring_set_default_keyring() [method@Service.set_alias]
gnome_keyring_set_default_keyring_sync() [method@Service.set_alias_sync]
gnome_keyring_get_default_keyring() [func@Collection.for_alias] with [const@COLLECTION_DEFAULT]
gnome_keyring_get_default_keyring_sync() [func@Collection.for_alias_sync] with [const@COLLECTION_DEFAULT]
gnome_keyring_list_item_ids() [method@Collection.load_items] and [method@Collection.get_items]
gnome_keyring_list_item_ids_sync() [method@Collection.load_items_sync] and [method@Collection.get_items]
GnomeKeyringInfo [class@Collection] and properties
gnome_keyring_get_info() no equivalent
gnome_keyring_get_info_sync() no equivalent
gnome_keyring_set_info() no equivalent, use property setters on [class@Collection]
gnome_keyring_set_info_sync() no equivalent, use property setters on [class@Collection]
gnome_keyring_info_free() no equivalent
gnome_keyring_info_copy() no equivalent
gnome_keyring_info_set_lock_on_idle() no equivalent
gnome_keyring_info_get_lock_on_idle() no equivalent
gnome_keyring_info_set_lock_timeout() no equivalent
gnome_keyring_info_get_lock_timeout() no equivalent
gnome_keyring_info_get_mtime() [method@Collection.get_modified]
gnome_keyring_info_get_ctime() [method@Collection.get_created]
gnome_keyring_info_get_is_locked() [method@Collection.get_locked]
## Locking and unlocking In libsecret you can unlock items directly, and the result is (with gnome-keyring daemon) that the enclosing collection will be unlocked. It is no longer possible to pass a password to unlock keyrings. These are automatically prompted for. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
gnome_keyring_unlock() [method@Service.unlock]
gnome_keyring_unlock_sync() [method@Service.unlock_sync]
gnome_keyring_lock() [method@Service.lock]
gnome_keyring_lock_sync() [method@Service.lock_sync]
gnome_keyring_lock_all() no equivalent, use platform specific DBus APIs
gnome_keyring_lock_all_sync() no equivalent, use platform specific DBus APIs
## Non-pageable memory libsecret no longer provides a full API for using non-pageable memory. Use the equivalent API in the Gcr library. You can request that passwords are returned in non-pageable memory by using the [func@password_lookup_nonpageable_sync] and [func@password_lookup_nonpageable_finish] functions. In addition the contents of [struct@Value] items is stored in non-pageable memory, unless the system doesn't support this. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
gnome_keyring_memory_alloc() no equivalent, use Gcr
gnome_keyring_memory_free() [func@password_free], although this only works on strings
gnome_keyring_memory_is_secure() no equivalent, use Gcr
gnome_keyring_memory_new() no equivalent, use Gcr
gnome_keyring_memory_realloc() no equivalent, use Gcr
gnome_keyring_memory_strdup() no equivalent, use [struct@Value] which is ref-counted, or use Gcr
gnome_keyring_memory_try_alloc() no equivalent, use Gcr
gnome_keyring_memory_try_realloc() no equivalent, use Gcr
gnome_keyring_free_password() [func@password_free]
## Errors and cancellation libsecret uses standard the standard [class@Gio.Cancellable] idiom to cancel operations. It is not necessary to check whether the keyring daemon is available before using it. It is started automatically. Errors are returned as standard [struct@GLib.Error] in the usual way. There are fewer errors that are worth handling in an intelligent way, exceptions are in the #SecretError enumeration. It is not recommended to display any [struct@GLib.Error] message returned by libsecret to the user. Most of the possible errors are DBus communication problems or similar. Replacements for related libgnome-keyring functions and types are described below:
libgnome-keyringlibsecret
gnome_keyring_cancel_request() [method@Gio.Cancellable.cancel] on a [class@Gio.Cancellable] passed to the relevant operation
gnome_keyring_is_available() no equivalent, the secret service is autostarted as necessary
gnome_keyring_result_to_message() use the message in the [struct@GLib.Error], although most failures are not appropriate for display to the user
GNOME_KEYRING_RESULT_OK no [struct@GLib.Error] returned
GNOME_KEYRING_RESULT_DENIED no longer used, item or collection is simply not unlocked
GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND
GNOME_KEYRING_RESULT_ALREADY_UNLOCKED no error, success returned
GNOME_KEYRING_RESULT_NO_SUCH_KEYRING keyrings no longer have names, accessing an missing DBus object has usual failure
GNOME_KEYRING_RESULT_BAD_ARGUMENTS G_DBUS_ERROR_INVALID_ARGS or precondition failure in libsecret, this is always a programmer error
GNOME_KEYRING_RESULT_IO_ERROR relevant DBus errors, or SECRET_ERROR_PROTOCOL
GNOME_KEYRING_RESULT_CANCELLED G_IO_ERROR_CANCELLED
GNOME_KEYRING_RESULT_KEYRING_ALREADY_EXISTS no error, simply returns already existing keyring
GNOME_KEYRING_RESULT_NO_MATCH on error, an empty list is returned
gnome_keyring_string_list_free() no equivalent
07070100000021000081A400000000000000000000000167D9F0D9000000E6000000000000000000000000000000000000003400000000libsecret-0.21.7/docs/reference/libsecret/urlmap.js// A map between namespaces and base URLs for their online documentation baseURLs = [ [ 'GLib', 'https://docs.gtk.org/glib/' ], [ 'GObject', 'https://docs.gtk.org/gobject/' ], [ 'Gio', 'https://docs.gtk.org/gio/' ], ] 07070100000022000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000001500000000libsecret-0.21.7/egg07070100000023000081A400000000000000000000000167D9F0D90000321A000000000000000000000000000000000000002200000000libsecret-0.21.7/egg/egg-buffer.c/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* egg-buffer.c - Generic data buffer, used by openssh, gnome-keyring Copyright (C) 2007 Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, . Author: Stef Walter */ #include "config.h" #include #include #include "egg-buffer.h" #define DEFAULT_ALLOCATOR ((EggBufferAllocator)realloc) int egg_buffer_init (EggBuffer *buffer, size_t reserve) { return egg_buffer_init_full (buffer, reserve, NULL); } int egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator) { memset (buffer, 0, sizeof (*buffer)); if (!allocator) allocator = DEFAULT_ALLOCATOR; if (reserve == 0) reserve = 64; buffer->buf = (allocator) (NULL, reserve); if (!buffer->buf) { buffer->failures++; return 0; } buffer->len = 0; buffer->allocated_len = reserve; buffer->failures = 0; buffer->allocator = allocator; return 1; } void egg_buffer_init_static (EggBuffer* buffer, const unsigned char *buf, size_t len) { memset (buffer, 0, sizeof (*buffer)); buffer->buf = (unsigned char*)buf; buffer->len = len; buffer->allocated_len = len; buffer->failures = 0; /* A null allocator, and the buffer can't change in size */ buffer->allocator = NULL; } void egg_buffer_init_allocated (EggBuffer *buffer, unsigned char *buf, size_t len, EggBufferAllocator allocator) { memset (buffer, 0, sizeof (*buffer)); if (!allocator) allocator = DEFAULT_ALLOCATOR; buffer->buf = buf; buffer->len = len; buffer->allocated_len = len; buffer->failures = 0; buffer->allocator = allocator; } void egg_buffer_reset (EggBuffer *buffer) { memset (buffer->buf, 0, buffer->allocated_len); buffer->len = 0; buffer->failures = 0; } void egg_buffer_uninit (EggBuffer *buffer) { if (!buffer) return; /* * Free the memory block using allocator. If no allocator, * then this memory is ownerd elsewhere and not to be freed. */ if (buffer->buf && buffer->allocator) (buffer->allocator) (buffer->buf, 0); memset (buffer, 0, sizeof (*buffer)); } unsigned char* egg_buffer_uninit_steal (EggBuffer *buffer, size_t *n_result) { unsigned char *result; if (n_result) *n_result = buffer->len; result = buffer->buf; memset (buffer, 0, sizeof (*buffer)); return result; } int egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator) { unsigned char *buf = NULL; if (!allocator) allocator = DEFAULT_ALLOCATOR; if (buffer->allocator == allocator) return 1; if (buffer->allocated_len) { /* Reallocate memory block using new allocator */ buf = (allocator) (NULL, buffer->allocated_len); if (buf == NULL) return 0; /* Copy stuff into new memory */ memcpy (buf, buffer->buf, buffer->allocated_len); } /* If old wasn't static, then free it */ if (buffer->allocator && buffer->buf) (buffer->allocator) (buffer->buf, 0); buffer->buf = buf; buffer->allocator = allocator; return 1; } int egg_buffer_equal (EggBuffer *b1, EggBuffer *b2) { if (b1->len != b2->len) return 0; return memcmp (b1->buf, b2->buf, b1->len) == 0; } int egg_buffer_reserve (EggBuffer *buffer, size_t len) { unsigned char *newbuf; size_t newlen; if (len < buffer->allocated_len) return 1; /* Calculate a new length, minimize number of buffer allocations */ newlen = buffer->allocated_len * 2; if (len > newlen) newlen += len; /* Memory owned elsewhere can't be reallocated */ if (!buffer->allocator) { buffer->failures++; return 0; } /* Reallocate built in buffer using allocator */ newbuf = (buffer->allocator) (buffer->buf, newlen); if (!newbuf) { buffer->failures++; return 0; } buffer->buf = newbuf; buffer->allocated_len = newlen; return 1; } int egg_buffer_resize (EggBuffer *buffer, size_t len) { if (!egg_buffer_reserve (buffer, len)) return 0; buffer->len = len; return 1; } unsigned char* egg_buffer_add_empty (EggBuffer *buffer, size_t len) { size_t pos = buffer->len; if (!egg_buffer_reserve (buffer, buffer->len + len)) return NULL; buffer->len += len; return buffer->buf + pos; } int egg_buffer_append (EggBuffer *buffer, const unsigned char *val, size_t len) { if (!egg_buffer_reserve (buffer, buffer->len + len)) return 0; /* failures already incremented */ memcpy (buffer->buf + buffer->len, val, len); buffer->len += len; return 1; } int egg_buffer_add_byte (EggBuffer *buffer, unsigned char val) { if (!egg_buffer_reserve (buffer, buffer->len + 1)) return 0; /* failures already incremented */ buffer->buf[buffer->len] = val; buffer->len++; return 1; } int egg_buffer_get_byte (EggBuffer *buffer, size_t offset, size_t *next_offset, unsigned char *val) { unsigned char *ptr; if (buffer->len < 1 || offset > buffer->len - 1) { buffer->failures++; return 0; } ptr = (unsigned char*)buffer->buf + offset; if (val != NULL) *val = *ptr; if (next_offset != NULL) *next_offset = offset + 1; return 1; } void egg_buffer_encode_uint16 (unsigned char* buf, uint16_t val) { buf[0] = (val >> 8) & 0xff; buf[1] = (val >> 0) & 0xff; } uint16_t egg_buffer_decode_uint16 (unsigned char* buf) { uint16_t val = buf[0] << 8 | buf[1]; return val; } int egg_buffer_add_uint16 (EggBuffer *buffer, uint16_t val) { if (!egg_buffer_reserve (buffer, buffer->len + 2)) return 0; /* failures already incremented */ buffer->len += 2; egg_buffer_set_uint16 (buffer, buffer->len - 2, val); return 1; } int egg_buffer_set_uint16 (EggBuffer *buffer, size_t offset, uint16_t val) { unsigned char *ptr; if (buffer->len < 2 || offset > buffer->len - 2) { buffer->failures++; return 0; } ptr = (unsigned char*)buffer->buf + offset; egg_buffer_encode_uint16 (ptr, val); return 1; } int egg_buffer_get_uint16 (EggBuffer *buffer, size_t offset, size_t *next_offset, uint16_t *val) { unsigned char *ptr; if (buffer->len < 2 || offset > buffer->len - 2) { buffer->failures++; return 0; } ptr = (unsigned char*)buffer->buf + offset; if (val != NULL) *val = egg_buffer_decode_uint16 (ptr); if (next_offset != NULL) *next_offset = offset + 2; return 1; } void egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val) { buf[0] = (val >> 24) & 0xff; buf[1] = (val >> 16) & 0xff; buf[2] = (val >> 8) & 0xff; buf[3] = (val >> 0) & 0xff; } uint32_t egg_buffer_decode_uint32 (unsigned char* ptr) { uint32_t val = (uint32_t) ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; return val; } int egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val) { if (!egg_buffer_reserve (buffer, buffer->len + 4)) return 0; /* failures already incremented */ buffer->len += 4; egg_buffer_set_uint32 (buffer, buffer->len - 4, val); return 1; } int egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val) { unsigned char *ptr; if (buffer->len < 4 || offset > buffer->len - 4) { buffer->failures++; return 0; } ptr = (unsigned char*)buffer->buf + offset; egg_buffer_encode_uint32 (ptr, val); return 1; } int egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset, uint32_t *val) { unsigned char *ptr; if (buffer->len < 4 || offset > buffer->len - 4) { buffer->failures++; return 0; } ptr = (unsigned char*)buffer->buf + offset; if (val != NULL) *val = egg_buffer_decode_uint32 (ptr); if (next_offset != NULL) *next_offset = offset + 4; return 1; } int egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val) { if (!egg_buffer_add_uint32 (buffer, ((val >> 32) & 0xffffffff))) return 0; return egg_buffer_add_uint32 (buffer, (val & 0xffffffff)); } int egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset, size_t *next_offset, uint64_t *val) { uint32_t a, b; if (!egg_buffer_get_uint32 (buffer, offset, &offset, &a)) return 0; if (!egg_buffer_get_uint32 (buffer, offset, &offset, &b)) return 0; if (val != NULL) *val = ((uint64_t)a) << 32 | b; if (next_offset != NULL) *next_offset = offset; return 1; } int egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val, size_t len) { if (val == NULL) return egg_buffer_add_uint32 (buffer, 0xffffffff); if (len >= 0x7fffffff) { buffer->failures++; return 0; } if (!egg_buffer_add_uint32 (buffer, len)) return 0; return egg_buffer_append (buffer, val, len); } unsigned char* egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen) { if (vlen >= 0x7fffffff) { buffer->failures++; return NULL; } if (!egg_buffer_add_uint32 (buffer, vlen)) return NULL; return egg_buffer_add_empty (buffer, vlen); } int egg_buffer_get_byte_array (EggBuffer *buffer, size_t offset, size_t *next_offset, const unsigned char **val, size_t *vlen) { uint32_t len; if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) return 0; if (len == 0xffffffff) { if (next_offset) *next_offset = offset; if (val) *val = NULL; if (vlen) *vlen = 0; return 1; } else if (len >= 0x7fffffff) { buffer->failures++; return 0; } if (buffer->len < len || offset > buffer->len - len) { buffer->failures++; return 0; } if (val) *val = buffer->buf + offset; if (vlen) *vlen = len; if (next_offset) *next_offset = offset + len; return 1; } int egg_buffer_add_string (EggBuffer *buffer, const char *str) { if (str == NULL) { return egg_buffer_add_uint32 (buffer, 0xffffffff); } else { size_t len = strlen (str); if (len >= 0x7fffffff) return 0; if (!egg_buffer_add_uint32 (buffer, len)) return 0; return egg_buffer_append (buffer, (unsigned char*)str, len); } } int egg_buffer_get_string (EggBuffer *buffer, size_t offset, size_t *next_offset, char **str_ret, EggBufferAllocator allocator) { uint32_t len; if (!allocator) allocator = buffer->allocator; if (!allocator) allocator = DEFAULT_ALLOCATOR; if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) { return 0; } if (len == 0xffffffff) { *next_offset = offset; *str_ret = NULL; return 1; } else if (len >= 0x7fffffff) { return 0; } if (buffer->len < len || offset > buffer->len - len) { return 0; } /* Make sure no null characters in string */ if (memchr (buffer->buf + offset, 0, len) != NULL) return 0; /* The passed allocator may be for non-pageable memory */ *str_ret = (allocator) (NULL, len + 1); if (!*str_ret) return 0; memcpy (*str_ret, buffer->buf + offset, len); /* Always zero terminate */ (*str_ret)[len] = 0; *next_offset = offset + len; return 1; } int egg_buffer_add_stringv (EggBuffer *buffer, const char** strv) { const char **v; uint32_t n = 0; if (!strv) return 0; /* Add the number of strings coming */ for (v = strv; *v; ++v) ++n; if (!egg_buffer_add_uint32 (buffer, n)) return 0; /* Add the individual strings */ for (v = strv; *v; ++v) { if (!egg_buffer_add_string (buffer, *v)) return 0; } return 1; } int egg_buffer_get_stringv (EggBuffer *buffer, size_t offset, size_t *next_offset, char ***strv_ret, EggBufferAllocator allocator) { uint32_t n, i, j; size_t len; if (!allocator) allocator = buffer->allocator; if (!allocator) allocator = DEFAULT_ALLOCATOR; /* First the number of environment variable lines */ if (!egg_buffer_get_uint32 (buffer, offset, &offset, &n)) return 0; /* Then that number of strings */ len = (n + 1) * sizeof (char*); *strv_ret = (char**)(allocator) (NULL, len); if (!*strv_ret) return 0; /* All null strings */ memset (*strv_ret, 0, len); for (i = 0; i < n; ++i) { if (!egg_buffer_get_string (buffer, offset, &offset, &((*strv_ret)[i]), allocator)) { /* Free all the strings on failure */ for (j = 0; j < i; ++j) { if ((*strv_ret)[j]) (allocator) ((*strv_ret)[j], 0); } return 0; } } if (next_offset != NULL) *next_offset = offset; return 1; } 07070100000024000081A400000000000000000000000167D9F0D900001B61000000000000000000000000000000000000002200000000libsecret-0.21.7/egg/egg-buffer.h/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* egg-buffer.h - Generic data buffer, used by openssh, gnome-keyring Copyright (C) 2007, Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, . Author: Stef Walter */ #ifndef EGG_BUFFER_H #define EGG_BUFFER_H #include #include /* ------------------------------------------------------------------- * EggBuffer * * IMPORTANT: This is pure vanila standard C, no glib. We need this * because certain consumers of this protocol need to be built * without linking in any special libraries. ie: the PKCS#11 module. * * Memory Allocation * * Callers can set their own allocator. If NULL is used then standard * C library heap memory is used and failures will not be fatal. Memory * failures will instead result in a zero return value or * egg_buffer_has_error() returning one. * * If you use something like g_realloc as the allocator, then memory * failures become fatal just like in a standard GTK program. * * Don't change the allocator manually in the EggBuffer structure. The * egg_buffer_set_allocator() func will reallocate and handle things * properly. * * Pointers into the Buffer * * Any write operation has the posibility of reallocating memory * and invalidating any direct pointers into the buffer. */ /* The allocator for the EggBuffer. This follows the realloc() syntax and logic */ typedef void* (*EggBufferAllocator) (void* p, size_t len); typedef struct _EggBuffer { unsigned char *buf; size_t len; size_t allocated_len; int failures; EggBufferAllocator allocator; } EggBuffer; #define EGG_BUFFER_EMPTY { NULL, 0, 0, 0, NULL } int egg_buffer_init (EggBuffer *buffer, size_t reserve); int egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator); void egg_buffer_init_static (EggBuffer *buffer, const unsigned char *buf, size_t len); void egg_buffer_init_allocated (EggBuffer *buffer, unsigned char *buf, size_t len, EggBufferAllocator allocator); void egg_buffer_uninit (EggBuffer *buffer); unsigned char* egg_buffer_uninit_steal (EggBuffer *buffer, size_t *n_result); int egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator); void egg_buffer_reset (EggBuffer *buffer); int egg_buffer_equal (EggBuffer *b1, EggBuffer *b2); int egg_buffer_reserve (EggBuffer *buffer, size_t len); int egg_buffer_resize (EggBuffer *buffer, size_t len); int egg_buffer_append (EggBuffer *buffer, const unsigned char *val, size_t len); unsigned char* egg_buffer_add_empty (EggBuffer *buffer, size_t len); int egg_buffer_add_byte (EggBuffer *buffer, unsigned char val); int egg_buffer_get_byte (EggBuffer *buffer, size_t offset, size_t *next_offset, unsigned char *val); void egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val); uint32_t egg_buffer_decode_uint32 (unsigned char* buf); int egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val); int egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val); int egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset, uint32_t *val); void egg_buffer_encode_uint16 (unsigned char* buf, uint16_t val); uint16_t egg_buffer_decode_uint16 (unsigned char* buf); int egg_buffer_add_uint16 (EggBuffer *buffer, uint16_t val); int egg_buffer_set_uint16 (EggBuffer *buffer, size_t offset, uint16_t val); int egg_buffer_get_uint16 (EggBuffer *buffer, size_t offset, size_t *next_offset, uint16_t *val); int egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val, size_t len); int egg_buffer_get_byte_array (EggBuffer *buffer, size_t offset, size_t *next_offset, const unsigned char **val, size_t *vlen); unsigned char* egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen); int egg_buffer_add_string (EggBuffer *buffer, const char *str); int egg_buffer_get_string (EggBuffer *buffer, size_t offset, size_t *next_offset, char **str_ret, EggBufferAllocator allocator); int egg_buffer_add_stringv (EggBuffer *buffer, const char** strv); int egg_buffer_get_stringv (EggBuffer *buffer, size_t offset, size_t *next_offset, char ***strv_ret, EggBufferAllocator allocator); int egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val); int egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset, size_t *next_offset, uint64_t *val); #define egg_buffer_length(b) ((b)->len) #define egg_buffer_has_error(b) ((b)->failures > 0) #endif /* EGG_BUFFER_H */ 07070100000025000081A400000000000000000000000167D9F0D900001603000000000000000000000000000000000000002500000000libsecret-0.21.7/egg/egg-dh-gnutls.c/* * libsecret * * Copyright (C) 2023 Daiki Ueno * * 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 copies of the GNU General Public License and * the GNU Lesser General Public License along with this program. If * not, see http://www.gnu.org/licenses/. * * Author: Daiki Ueno */ #include "config.h" #include "egg-dh.h" /* Enabling this is a complete security compromise */ #define DEBUG_DH_SECRET 0 #include #include struct egg_dh_params { gnutls_dh_params_t inner; guint bits; }; struct egg_dh_pubkey { gnutls_pubkey_t inner; }; struct egg_dh_privkey { gnutls_privkey_t inner; }; egg_dh_params * egg_dh_default_params (const gchar *name) { const egg_dh_group *group; egg_dh_params *params; g_return_val_if_fail (name, NULL); for (group = egg_dh_groups; group->name; ++group) { if (g_str_equal (group->name, name)) { gnutls_dh_params_t inner; gnutls_datum_t prime, generator; int ret; ret = gnutls_dh_params_init (&inner); if (ret < 0) return NULL; prime.data = (void *)group->prime; prime.size = group->n_prime; generator.data = (void *)group->base; generator.size = group->n_base; ret = gnutls_dh_params_import_raw (inner, &prime, &generator); if (ret < 0) { gnutls_dh_params_deinit (inner); return NULL; } params = g_new (struct egg_dh_params, 1); if (!params) { gnutls_dh_params_deinit (inner); return NULL; } params->inner = g_steal_pointer (&inner); params->bits = group->bits; return params; } } return NULL; } gboolean egg_dh_gen_pair (egg_dh_params *params, guint bits, egg_dh_pubkey **pub, egg_dh_privkey **priv) { gnutls_pubkey_t pub_inner = NULL; gnutls_privkey_t priv_inner = NULL; egg_dh_pubkey *pub_outer = NULL; egg_dh_privkey *priv_outer = NULL; gnutls_keygen_data_st data; gboolean ok = FALSE; int ret; g_return_val_if_fail (params, FALSE); g_return_val_if_fail (pub, FALSE); g_return_val_if_fail (priv, FALSE); if (bits == 0) bits = params->bits; else if (bits > params->bits) g_return_val_if_reached (FALSE); ret = gnutls_privkey_init (&priv_inner); if (ret < 0) goto out; data.type = GNUTLS_KEYGEN_DH; data.data = (void *)params->inner; ret = gnutls_privkey_generate2 (priv_inner, GNUTLS_PK_DH, bits, 0, &data, 1); if (ret < 0) goto out; ret = gnutls_pubkey_init (&pub_inner); if (ret < 0) goto out; ret = gnutls_pubkey_import_privkey (pub_inner, priv_inner, 0, 0); if (ret < 0) goto out; pub_outer = g_new0 (struct egg_dh_pubkey, 1); if (!pub_outer) goto out; pub_outer->inner = g_steal_pointer (&pub_inner); priv_outer = g_new0 (struct egg_dh_privkey, 1); if (!priv_outer) goto out; priv_outer->inner = g_steal_pointer (&priv_inner); *pub = g_steal_pointer (&pub_outer); *priv = g_steal_pointer (&priv_outer); ok = TRUE; out: if (priv_inner) gnutls_privkey_deinit (priv_inner); if (pub_inner) gnutls_pubkey_deinit (pub_inner); egg_dh_privkey_free (priv_outer); egg_dh_pubkey_free (pub_outer); return ok; } GBytes * egg_dh_gen_secret (egg_dh_pubkey *peer, egg_dh_privkey *priv, egg_dh_params *params) { int ret; gnutls_datum_t k; #if DEBUG_DH_SECRET gnutls_datum_t h; #endif g_return_val_if_fail (peer, NULL); g_return_val_if_fail (priv, NULL); g_return_val_if_fail (params, NULL); ret = gnutls_privkey_derive_secret (priv->inner, peer->inner, NULL, &k, 0); if (ret < 0) return NULL; #if DEBUG_DH_SECRET ret = gnutls_hex_encode2 (&k, &h); g_assert (ret >= 0); g_printerr ("DH SECRET: %s\n", h.data); gnutls_free (h.data); #endif return g_bytes_new_with_free_func (k.data, k.size, (GDestroyNotify)gnutls_free, k.data); } void egg_dh_params_free (egg_dh_params *params) { gnutls_dh_params_deinit (params->inner); g_free (params); } void egg_dh_pubkey_free (egg_dh_pubkey *pubkey) { if (!pubkey) return; if (pubkey->inner) gnutls_pubkey_deinit (pubkey->inner); g_free (pubkey); } void egg_dh_privkey_free (egg_dh_privkey *privkey) { if (!privkey) return; if (privkey->inner) gnutls_privkey_deinit (privkey->inner); g_free (privkey); } GBytes * egg_dh_pubkey_export (const egg_dh_pubkey *pubkey) { gnutls_datum_t data; int ret; ret = gnutls_pubkey_export_dh_raw (pubkey->inner, NULL, &data, 0); if (ret < 0) return NULL; return g_bytes_new_with_free_func (data.data, data.size, (GDestroyNotify)gnutls_free, data.data); } egg_dh_pubkey * egg_dh_pubkey_new_from_bytes (const egg_dh_params *params, GBytes *bytes) { egg_dh_pubkey *pub; gnutls_pubkey_t inner; gnutls_datum_t data; int ret; ret = gnutls_pubkey_init (&inner); if (ret < 0) return NULL; data.data = (void *)g_bytes_get_data (bytes, NULL); data.size = g_bytes_get_size (bytes); ret = gnutls_pubkey_import_dh_raw (inner, params->inner, &data); if (ret < 0) { gnutls_pubkey_deinit (inner); return NULL; } pub = g_new (struct egg_dh_pubkey, 1); if (!pub) { gnutls_pubkey_deinit (inner); return NULL; } pub->inner = g_steal_pointer (&inner); return pub; } 07070100000026000081A400000000000000000000000167D9F0D9000019D4000000000000000000000000000000000000002800000000libsecret-0.21.7/egg/egg-dh-libgcrypt.c/* * gnome-keyring * * Copyright (C) 2009 Stefan Walter * * 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 copies of the GNU General Public License and * the GNU Lesser General Public License along with this program. If * not, see http://www.gnu.org/licenses/. * * Author: Stef Walter */ #include "config.h" #include "egg-dh.h" #include #include "egg-secure-memory.h" /* Enabling this is a complete security compromise */ #define DEBUG_DH_SECRET 0 EGG_SECURE_DECLARE (dh); struct egg_dh_params { gcry_mpi_t prime; gcry_mpi_t base; }; struct egg_dh_pubkey { gcry_mpi_t inner; }; struct egg_dh_privkey { gcry_mpi_t inner; }; egg_dh_params * egg_dh_default_params (const gchar *name) { const egg_dh_group *group; gcry_error_t gcry; gcry_mpi_t prime = NULL, base = NULL; egg_dh_params *params = NULL; g_return_val_if_fail (name, NULL); for (group = egg_dh_groups; group->name; ++group) if (g_str_equal (group->name, name)) break; if (!group->name) return NULL; gcry = gcry_mpi_scan (&prime, GCRYMPI_FMT_USG, group->prime, group->n_prime, NULL); g_return_val_if_fail (gcry == 0, NULL); g_return_val_if_fail (gcry_mpi_get_nbits (prime) == group->bits, NULL); gcry = gcry_mpi_scan (&base, GCRYMPI_FMT_USG, group->base, group->n_base, NULL); g_return_val_if_fail (gcry == 0, NULL); params = g_new (struct egg_dh_params, 1); if (!params) goto error; params->prime = g_steal_pointer (&prime); params->base = g_steal_pointer (&base); error: gcry_mpi_release (prime); gcry_mpi_release (base); return params; } gboolean egg_dh_gen_pair (egg_dh_params *params, guint bits, egg_dh_pubkey **pub, egg_dh_privkey **priv) { guint pbits; gcry_mpi_t pub_inner = NULL, priv_inner = NULL; g_return_val_if_fail (params, FALSE); g_return_val_if_fail (pub, FALSE); g_return_val_if_fail (priv, FALSE); *pub = NULL; *priv = NULL; pbits = gcry_mpi_get_nbits (params->prime); g_return_val_if_fail (pbits > 1, FALSE); if (bits == 0) { bits = pbits; } else if (bits > pbits) { g_return_val_if_reached (FALSE); } /* * Generate a strong random number of bits, and not zero. * gcry_mpi_randomize bumps up to the next byte. Since we * need to have a value less than half of prime, we make sure * we bump down. */ priv_inner = gcry_mpi_snew (bits); g_return_val_if_fail (priv_inner, FALSE); while (gcry_mpi_cmp_ui (priv_inner, 0) == 0) gcry_mpi_randomize (priv_inner, bits, GCRY_STRONG_RANDOM); /* Secret key value must be less than half of p */ if (gcry_mpi_get_nbits (priv_inner) > bits) gcry_mpi_clear_highbit (priv_inner, bits); if (gcry_mpi_get_nbits (priv_inner) > pbits - 1) gcry_mpi_clear_highbit (priv_inner, pbits - 1); g_assert (gcry_mpi_cmp (params->prime, priv_inner) > 0); pub_inner = gcry_mpi_new (gcry_mpi_get_nbits (priv_inner)); if (!pub_inner) goto error; gcry_mpi_powm (pub_inner, params->base, priv_inner, params->prime); *priv = g_new0 (struct egg_dh_privkey, 1); if (!*priv) goto error; (*priv)->inner = g_steal_pointer (&priv_inner); *pub = g_new0 (struct egg_dh_pubkey, 1); if (!*pub) goto error; (*pub)->inner = g_steal_pointer (&pub_inner); return TRUE; error: egg_dh_privkey_free (*priv); egg_dh_pubkey_free (*pub); gcry_mpi_release (priv_inner); gcry_mpi_release (pub_inner); g_return_val_if_reached (FALSE); } GBytes * egg_dh_gen_secret (egg_dh_pubkey *peer, egg_dh_privkey *priv, egg_dh_params *params) { gcry_error_t gcry; guchar *value; gsize n_prime; gsize n_value; gcry_mpi_t k; gint bits; g_return_val_if_fail (peer, NULL); g_return_val_if_fail (priv, NULL); g_return_val_if_fail (params, NULL); bits = gcry_mpi_get_nbits (params->prime); g_return_val_if_fail (bits >= 0, NULL); k = gcry_mpi_snew (bits); g_return_val_if_fail (k, NULL); gcry_mpi_powm (k, peer->inner, priv->inner, params->prime); /* Write out the secret */ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_prime, params->prime); g_return_val_if_fail (gcry == 0, NULL); value = egg_secure_alloc (n_prime); if (!value) return NULL; gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value, n_prime, &n_value, k); g_return_val_if_fail (gcry == 0, NULL); /* Pad the secret with zero bytes to match length of prime in bytes. */ if (n_value < n_prime) { memmove (value + (n_prime - n_value), value, n_value); memset (value, 0, (n_prime - n_value)); } #if DEBUG_DH_SECRET g_printerr ("DH SECRET: "); gcry_mpi_dump (k); #endif gcry_mpi_release (k); #if DEBUG_DH_SECRET gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, n_prime, NULL); g_printerr ("RAW SECRET: "); gcry_mpi_dump (k); gcry_mpi_release (k); #endif return g_bytes_new_with_free_func (value, n_prime, (GDestroyNotify)egg_secure_free, value); } void egg_dh_params_free (egg_dh_params *params) { if (!params) return; gcry_mpi_release (params->prime); gcry_mpi_release (params->base); g_free (params); } void egg_dh_pubkey_free (egg_dh_pubkey *pubkey) { if (!pubkey) return; if (pubkey->inner) gcry_mpi_release (pubkey->inner); g_free (pubkey); } void egg_dh_privkey_free (egg_dh_privkey *privkey) { if (!privkey) return; if (privkey->inner) gcry_mpi_release (privkey->inner); g_free (privkey); } GBytes * egg_dh_pubkey_export (const egg_dh_pubkey *pubkey) { gcry_error_t gcry; unsigned char *buffer; size_t n_buffer; gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer, pubkey->inner); g_return_val_if_fail (gcry == 0, NULL); return g_bytes_new_with_free_func (buffer, n_buffer, gcry_free, buffer); } egg_dh_pubkey * egg_dh_pubkey_new_from_bytes (const egg_dh_params *params, GBytes *bytes) { gcry_error_t gcry; gcry_mpi_t inner; egg_dh_pubkey *pub; gcry = gcry_mpi_scan (&inner, GCRYMPI_FMT_USG, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL); if (gcry != 0) return NULL; pub = g_new (struct egg_dh_pubkey, 1); if (!pub) { gcry_mpi_release (inner); return NULL; } pub->inner = inner; return pub; } 07070100000027000081A400000000000000000000000167D9F0D9000047AF000000000000000000000000000000000000001E00000000libsecret-0.21.7/egg/egg-dh.c/* * gnome-keyring * * Copyright (C) 2009 Stefan Walter * * 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 copies of the GNU General Public License and * the GNU Lesser General Public License along with this program. If * not, see http://www.gnu.org/licenses/. * * Author: Stef Walter */ #include "config.h" #include "egg-dh.h" static const guchar dh_group_768_prime[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const guchar dh_group_1024_prime[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const guchar dh_group_1536_prime[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const guchar dh_group_2048_prime[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const guchar dh_group_3072_prime[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const guchar dh_group_4096_prime[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const guchar dh_group_8192_prime[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59, 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4, 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, 0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA, 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, 0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66, 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68, 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, 0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D, 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7, 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B, 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, 0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8, 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, 0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D, 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36, 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, 0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D, 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, 0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68, 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92, 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, 0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B, 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, 0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71, 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; const egg_dh_group egg_dh_groups[] = { { "ietf-ike-grp-modp-768", 768, dh_group_768_prime, G_N_ELEMENTS (dh_group_768_prime), { 0x02 }, 1 }, { "ietf-ike-grp-modp-1024", 1024, dh_group_1024_prime, G_N_ELEMENTS (dh_group_1024_prime), { 0x02 }, 1 }, { "ietf-ike-grp-modp-1536", 1536, dh_group_1536_prime, G_N_ELEMENTS (dh_group_1536_prime), { 0x02 }, 1 }, { "ietf-ike-grp-modp-2048", 2048, dh_group_2048_prime, G_N_ELEMENTS (dh_group_2048_prime), { 0x02 }, 1 }, { "ietf-ike-grp-modp-3072", 3072, dh_group_3072_prime, G_N_ELEMENTS (dh_group_3072_prime), { 0x02 }, 1 }, { "ietf-ike-grp-modp-4096", 4096, dh_group_4096_prime, G_N_ELEMENTS (dh_group_4096_prime), { 0x02 }, 1 }, { "ietf-ike-grp-modp-8192", 8192, dh_group_8192_prime, G_N_ELEMENTS (dh_group_8192_prime), { 0x02 }, 1 }, { NULL } }; gboolean egg_dh_default_params_raw (const gchar *name, gconstpointer *prime, gsize *n_prime, gconstpointer *base, gsize *n_base) { const egg_dh_group *group; g_return_val_if_fail (name, FALSE); g_return_val_if_fail (prime, FALSE); g_return_val_if_fail (n_prime, FALSE); g_return_val_if_fail (base, FALSE); g_return_val_if_fail (n_base, FALSE); for (group = egg_dh_groups; group->name; ++group) { if (g_str_equal (group->name, name)) { *prime = group->prime; *n_prime = group->n_prime; *base = group->base; *n_base = group->n_base; return TRUE; } } return FALSE; } 07070100000028000081A400000000000000000000000167D9F0D9000009D0000000000000000000000000000000000000001E00000000libsecret-0.21.7/egg/egg-dh.h/* * gnome-keyring * * Copyright (C) 2009 Stefan Walter * * 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 * * Author: Stef Walter */ #ifndef EGG_DH_H_ #define EGG_DH_H_ #include typedef struct egg_dh_params egg_dh_params; typedef struct egg_dh_pubkey egg_dh_pubkey; typedef struct egg_dh_privkey egg_dh_privkey; typedef struct egg_dh_group { const gchar *name; guint bits; const guchar *prime; gsize n_prime; const guchar base[1]; gsize n_base; } egg_dh_group; extern const egg_dh_group egg_dh_groups[]; egg_dh_params *egg_dh_default_params (const gchar *name); gboolean egg_dh_default_params_raw (const gchar *name, gconstpointer *prime, gsize *n_prime, gconstpointer *base, gsize *n_base); gboolean egg_dh_gen_pair (egg_dh_params *params, guint bits, egg_dh_pubkey **pub, egg_dh_privkey **priv); GBytes *egg_dh_gen_secret (egg_dh_pubkey *peer, egg_dh_privkey *priv, egg_dh_params *prime); void egg_dh_params_free (egg_dh_params *params); void egg_dh_pubkey_free (egg_dh_pubkey *pubkey); void egg_dh_privkey_free (egg_dh_privkey *privkey); GBytes *egg_dh_pubkey_export (const egg_dh_pubkey *pubkey); egg_dh_pubkey *egg_dh_pubkey_new_from_bytes (const egg_dh_params *params, GBytes *bytes); #endif /* EGG_DH_H_ */ 07070100000029000081A400000000000000000000000167D9F0D9000003E4000000000000000000000000000000000000002700000000libsecret-0.21.7/egg/egg-fips-gnutls.c/* * libsecret * * Copyright (C) 2024 Red Hat, Inc. * * 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, see . */ #include "config.h" #include "egg-fips.h" #include EggFipsMode egg_fips_get_mode (void) { return gnutls_fips140_mode_enabled (); } void egg_fips_set_mode (EggFipsMode mode) { gnutls_fips140_set_mode (mode, GNUTLS_FIPS140_SET_MODE_THREAD); } 0707010000002A000081A400000000000000000000000167D9F0D90000038B000000000000000000000000000000000000002A00000000libsecret-0.21.7/egg/egg-fips-libgcrypt.c/* * libsecret * * Copyright (C) 2024 Red Hat, Inc. * * 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, see . */ #include "config.h" #include "egg-fips.h" EggFipsMode egg_fips_get_mode (void) { return EGG_FIPS_MODE_DISABLED; } void egg_fips_set_mode (EggFipsMode mode) { (void)mode; } 0707010000002B000081A400000000000000000000000167D9F0D9000003DC000000000000000000000000000000000000002000000000libsecret-0.21.7/egg/egg-fips.h/* * libsecret * * Copyright (C) 2024 Red Hat, Inc. * * 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, see . */ #ifndef EGG_FIPS_H_ #define EGG_FIPS_H_ typedef enum { EGG_FIPS_MODE_DISABLED = 0, /* Other values are specific to each backend */ } EggFipsMode; EggFipsMode egg_fips_get_mode (void); void egg_fips_set_mode (EggFipsMode mode); #endif /* EGG_FIPS_H_ */ 0707010000002C000081A400000000000000000000000167D9F0D900000D7D000000000000000000000000000000000000001F00000000libsecret-0.21.7/egg/egg-hex.c/* * gnome-keyring * * Copyright (C) 2008 Stefan Walter * * 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 * * Author: Stef Walter */ #include "config.h" #include "egg-hex.h" #include static const char HEXC_UPPER[] = "0123456789ABCDEF"; static const char HEXC_LOWER[] = "0123456789abcdef"; gpointer egg_hex_decode (const gchar *data, gssize n_data, gsize *n_decoded) { return egg_hex_decode_full (data, n_data, 0, 1, n_decoded); } gpointer egg_hex_decode_full (const gchar *data, gssize n_data, const gchar *delim, guint group, gsize *n_decoded) { guchar *result; guchar *decoded; gsize n_delim; gushort j; gint state = 0; gint part = 0; const gchar* pos; g_return_val_if_fail (data || !n_data, NULL); g_return_val_if_fail (n_decoded, NULL); g_return_val_if_fail (group >= 1, NULL); if (n_data == -1) n_data = strlen (data); n_delim = delim ? strlen (delim) : 0; decoded = result = g_malloc0 ((n_data / 2) + 1); *n_decoded = 0; while (n_data > 0 && state == 0) { if (decoded != result && delim) { if (n_data < n_delim || memcmp (data, delim, n_delim) != 0) { state = -1; break; } data += n_delim; n_data -= n_delim; } while (part < group && n_data > 0) { /* Find the position */ pos = strchr (HEXC_UPPER, g_ascii_toupper (*data)); if (pos == 0) { if (n_data > 0) state = -1; break; } j = pos - HEXC_UPPER; if(!state) { *decoded = (j & 0xf) << 4; state = 1; } else { *decoded |= (j & 0xf); (*n_decoded)++; decoded++; state = 0; part++; } ++data; --n_data; } part = 0; } /* Parsing error */ if (state != 0) { g_free (result); result = NULL; } return result; } gchar* egg_hex_encode (gconstpointer data, gsize n_data) { return egg_hex_encode_full (data, n_data, TRUE, NULL, 0); } gchar* egg_hex_encode_full (gconstpointer data, gsize n_data, gboolean upper_case, const gchar *delim, guint group) { GString *result; const gchar *input; const char *hexc; gsize bytes; guchar j; g_return_val_if_fail (data || !n_data, NULL); input = data; hexc = upper_case ? HEXC_UPPER : HEXC_LOWER; result = g_string_sized_new (n_data * 2 + 1); bytes = 0; while (n_data > 0) { if (delim && group && bytes && (bytes % group) == 0) g_string_append (result, delim); j = *(input) >> 4 & 0xf; g_string_append_c (result, hexc[j]); j = *(input++) & 0xf; g_string_append_c (result, hexc[j]); ++bytes; --n_data; } /* Make sure still null terminated */ return g_string_free (result, FALSE); } 0707010000002D000081A400000000000000000000000167D9F0D900000858000000000000000000000000000000000000001F00000000libsecret-0.21.7/egg/egg-hex.h/* * gnome-keyring * * Copyright (C) 2008 Stefan Walter * * 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 * * Author: Stef Walter */ #ifndef EGG_HEX_H_ #define EGG_HEX_H_ #include gpointer egg_hex_decode (const gchar *data, gssize n_data, gsize *n_decoded); gpointer egg_hex_decode_full (const gchar *data, gssize n_data, const gchar *delim, guint group, gsize *n_decoded); gchar* egg_hex_encode (gconstpointer data, gsize n_data); gchar* egg_hex_encode_full (gconstpointer data, gsize n_data, gboolean upper_case, const gchar *delim, guint group); #endif /* EGG_HEX_H_ */ 0707010000002E000081A400000000000000000000000167D9F0D900000AED000000000000000000000000000000000000002700000000libsecret-0.21.7/egg/egg-hkdf-gnutls.c/* * libsecret * * Copyright (C) 2023 Daiki Ueno * * 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 copies of the GNU General Public License and * the GNU Lesser General Public License along with this program. If * not, see http://www.gnu.org/licenses/. * * Author: Daiki Ueno */ #include "config.h" #include "egg-hkdf.h" #include "egg-secure-memory.h" #include EGG_SECURE_DECLARE (hkdf); gboolean egg_hkdf_perform (const gchar *hash_algo, gconstpointer input, gsize n_input, gconstpointer salt, gsize n_salt, gconstpointer info, gsize n_info, gpointer output, gsize n_output) { static const struct { gchar *name; gnutls_mac_algorithm_t algo; } hash_algos[] = { { "sha1", GNUTLS_MAC_SHA1 }, { "sha256", GNUTLS_MAC_SHA256 }, { NULL, } }; gnutls_mac_algorithm_t algo = GNUTLS_MAC_UNKNOWN; gnutls_datum_t input_datum, salt_datum, info_datum; gpointer alloc = NULL; gpointer buffer = NULL; guint hash_len; gsize i; int ret; gboolean result = TRUE; for (i = 0; hash_algos[i].name; i++) { if (g_str_equal (hash_algos[i].name, hash_algo)) { algo = hash_algos[i].algo; break; } } g_return_val_if_fail (algo != GNUTLS_MAC_UNKNOWN, FALSE); hash_len = gnutls_hmac_get_len (algo); g_return_val_if_fail (hash_len != 0, FALSE); g_return_val_if_fail (n_output <= 255 * hash_len, FALSE); /* Buffer we need to for intermediate stuff */ buffer = egg_secure_alloc (hash_len); g_return_val_if_fail (buffer, FALSE); /* Salt defaults to hash_len zeros */ if (!salt) { alloc = g_malloc0 (hash_len); if (!alloc) { result = FALSE; goto out; } salt = alloc; n_salt = hash_len; } /* Step 1: Extract */ input_datum.data = (void *)input; input_datum.size = n_input; salt_datum.data = (void *)salt; salt_datum.size = n_salt; ret = gnutls_hkdf_extract (algo, &input_datum, &salt_datum, buffer); if (ret < 0) { result = FALSE; goto out; } /* Step 2: Expand */ input_datum.data = buffer; input_datum.size = hash_len; info_datum.data = (void *)info; info_datum.size = n_info; ret = gnutls_hkdf_expand (algo, &input_datum, &info_datum, output, n_output); if (ret < 0) { result = FALSE; goto out; } out: g_free (alloc); egg_secure_free (buffer); return result; } 0707010000002F000081A400000000000000000000000167D9F0D900000B4E000000000000000000000000000000000000002A00000000libsecret-0.21.7/egg/egg-hkdf-libgcrypt.c/* * gnome-keyring * * Copyright (C) 2011 Collabora Ltd. * * 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 copies of the GNU General Public License and * the GNU Lesser General Public License along with this program. If * not, see http://www.gnu.org/licenses/. * * Author: Stef Walter */ #include "config.h" #include "egg-hkdf.h" #include #include gboolean egg_hkdf_perform (const gchar *hash_algo, gconstpointer input, gsize n_input, gconstpointer salt, gsize n_salt, gconstpointer info, gsize n_info, gpointer output, gsize n_output) { gpointer alloc = NULL; gpointer buffer = NULL; gcry_md_hd_t md1, md2; guint hash_len; gint i; gint flags, algo; gsize step, n_buffer; guchar *at; gcry_error_t gcry; algo = gcry_md_map_name (hash_algo); g_return_val_if_fail (algo != 0, FALSE); hash_len = gcry_md_get_algo_dlen (algo); g_return_val_if_fail (hash_len != 0, FALSE); g_return_val_if_fail (n_output <= 255 * hash_len, FALSE); /* Buffer we need to for intermediate stuff */ if (gcry_is_secure (input)) { flags = GCRY_MD_FLAG_SECURE; buffer = gcry_malloc_secure (hash_len); } else { flags = 0; buffer = gcry_malloc (hash_len); } g_return_val_if_fail (buffer, FALSE); n_buffer = 0; /* Salt defaults to hash_len zeros */ if (!salt) { salt = alloc = g_malloc0 (hash_len); n_salt = hash_len; } /* Step 1: Extract */ gcry = gcry_md_open (&md1, algo, GCRY_MD_FLAG_HMAC | flags); g_return_val_if_fail (gcry == 0, FALSE); gcry = gcry_md_setkey (md1, salt, n_salt); g_return_val_if_fail (gcry == 0, FALSE); gcry_md_write (md1, input, n_input); /* Step 2: Expand */ gcry = gcry_md_open (&md2, algo, GCRY_MD_FLAG_HMAC | flags); g_return_val_if_fail (gcry == 0, FALSE); gcry = gcry_md_setkey (md2, gcry_md_read (md1, algo), hash_len); g_return_val_if_fail (gcry == 0, FALSE); gcry_md_close (md1); at = output; for (i = 1; i < 256; ++i) { gcry_md_reset (md2); gcry_md_write (md2, buffer, n_buffer); gcry_md_write (md2, info, n_info); gcry_md_putc (md2, i); n_buffer = hash_len; memcpy (buffer, gcry_md_read (md2, algo), n_buffer); step = MIN (n_buffer, n_output); memcpy (at, buffer, step); n_output -= step; at += step; if (!n_output) break; } g_free (alloc); gcry_free (buffer); gcry_md_close (md2); return TRUE; } 07070100000030000081A400000000000000000000000167D9F0D900000691000000000000000000000000000000000000002000000000libsecret-0.21.7/egg/egg-hkdf.h/* * gnome-keyring * * Copyright (C) 2011 Collabora Ltd. * * 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 * * Author: Stef Walter */ #ifndef EGG_HKDF_H_ #define EGG_HKDF_H_ #include gboolean egg_hkdf_perform (const gchar *hash_algo, gconstpointer input, gsize n_input, gconstpointer salt, gsize n_salt, gconstpointer info, gsize n_info, gpointer output, gsize n_output); #endif /* EGG_HKDF_H_ */ 07070100000031000081A400000000000000000000000167D9F0D900000D7F000000000000000000000000000000000000002B00000000libsecret-0.21.7/egg/egg-keyring1-gnutls.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #include "config.h" #include "egg-keyring1.h" #include "egg/egg-secure-memory.h" EGG_SECURE_DECLARE (egg_keyring1); #include #define PBKDF2_HASH_ALGO GNUTLS_MAC_SHA256 #define MAC_ALGO GNUTLS_MAC_SHA256 #define CIPHER_ALGO GNUTLS_CIPHER_AES_128_CBC void egg_keyring1_create_nonce (guint8 *nonce, gsize nonce_size) { (void)gnutls_rnd (GNUTLS_RND_NONCE, nonce, nonce_size); } GBytes * egg_keyring1_derive_key (const char *password, gsize n_password, GBytes *salt, guint32 iteration_count) { gnutls_datum_t password_datum, salt_datum; guint8 *buffer; int ret; password_datum.data = (void *)password; password_datum.size = n_password; salt_datum.data = (void *)g_bytes_get_data (salt, NULL); salt_datum.size = g_bytes_get_size (salt); buffer = egg_secure_alloc (KEY_SIZE); g_return_val_if_fail (buffer, NULL); ret = gnutls_pbkdf2 (PBKDF2_HASH_ALGO, &password_datum, &salt_datum, iteration_count, buffer, KEY_SIZE); if (ret < 0) { egg_secure_free (buffer); return NULL; } return g_bytes_new_with_free_func (buffer, KEY_SIZE, egg_secure_free, buffer); } gboolean egg_keyring1_calculate_mac (GBytes *key, const guint8 *value, gsize n_value, guint8 *buffer) { return gnutls_hmac_fast (MAC_ALGO, g_bytes_get_data (key, NULL), g_bytes_get_size (key), value, n_value, buffer) >= 0; } gboolean egg_keyring1_verify_mac (GBytes *key, const guint8 *value, gsize n_value, const guint8 *data) { guint8 buffer[MAC_SIZE]; guint8 status = 0; gsize i; if (!egg_keyring1_calculate_mac (key, value, n_value, buffer)) { return FALSE; } for (i = 0; i < MAC_SIZE; i++) { status |= data[i] ^ buffer[i]; } return status == 0; } gboolean egg_keyring1_decrypt (GBytes *key, guint8 *data, gsize n_data) { gnutls_cipher_hd_t hd = NULL; int ret; gsize n_secret; gnutls_datum_t key_datum, iv_datum; key_datum.data = (void *)g_bytes_get_data (key, &n_secret); key_datum.size = n_secret; iv_datum.data = data + n_data; iv_datum.size = IV_SIZE; ret = gnutls_cipher_init (&hd, CIPHER_ALGO, &key_datum, &iv_datum); if (ret < 0) { return FALSE; } ret = gnutls_cipher_decrypt2 (hd, data, n_data, data, n_data); if (ret < 0) { gnutls_cipher_deinit (hd); return FALSE; } gnutls_cipher_deinit (hd); return TRUE; } gboolean egg_keyring1_encrypt (GBytes *key, guint8 *data, gsize n_data) { gnutls_cipher_hd_t hd = NULL; int ret; gsize n_secret; gnutls_datum_t key_datum, iv_datum; key_datum.data = (void *)g_bytes_get_data (key, &n_secret); key_datum.size = n_secret; iv_datum.data = data + n_data; iv_datum.size = IV_SIZE; egg_keyring1_create_nonce (iv_datum.data, iv_datum.size); ret = gnutls_cipher_init (&hd, CIPHER_ALGO, &key_datum, &iv_datum); g_return_val_if_fail (ret >= 0, FALSE); ret = gnutls_cipher_encrypt2 (hd, data, n_data, data, n_data); gnutls_cipher_deinit (hd); return ret < 0 ? FALSE : TRUE; } 07070100000032000081A400000000000000000000000167D9F0D900000EFF000000000000000000000000000000000000002E00000000libsecret-0.21.7/egg/egg-keyring1-libgcrypt.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #include "config.h" #include "egg-keyring1.h" #include "egg/egg-secure-memory.h" EGG_SECURE_DECLARE (egg_keyring1); #include #define PBKDF2_HASH_ALGO GCRY_MD_SHA256 #define MAC_ALGO GCRY_MAC_HMAC_SHA256 #define CIPHER_ALGO GCRY_CIPHER_AES128 void egg_keyring1_create_nonce (guint8 *nonce, gsize nonce_size) { gcry_create_nonce (nonce, nonce_size); } GBytes * egg_keyring1_derive_key (const gchar *password, gsize n_password, GBytes *salt, guint32 iteration_count) { guint8 *buffer; gcry_error_t gcry; buffer = egg_secure_alloc (KEY_SIZE); g_return_val_if_fail (buffer, NULL); gcry = gcry_kdf_derive (password, n_password, GCRY_KDF_PBKDF2, PBKDF2_HASH_ALGO, g_bytes_get_data (salt, NULL), g_bytes_get_size (salt), iteration_count, KEY_SIZE, buffer); if (gcry != 0) { egg_secure_free (buffer); return NULL; } return g_bytes_new_with_free_func (buffer, KEY_SIZE, egg_secure_free, buffer); } gboolean egg_keyring1_calculate_mac (GBytes *key, const guint8 *value, gsize n_value, guint8 *buffer) { gcry_mac_hd_t hd; gcry_error_t gcry; gconstpointer secret; gsize n_secret; gboolean ret = FALSE; gcry = gcry_mac_open (&hd, MAC_ALGO, 0, NULL); g_return_val_if_fail (gcry == 0, FALSE); secret = g_bytes_get_data (key, &n_secret); gcry = gcry_mac_setkey (hd, secret, n_secret); if (gcry != 0) goto out; gcry = gcry_mac_write (hd, value, n_value); if (gcry != 0) goto out; n_value = MAC_SIZE; gcry = gcry_mac_read (hd, buffer, &n_value); if (gcry != 0) goto out; if (n_value != MAC_SIZE) goto out; ret = TRUE; out: gcry_mac_close (hd); return ret; } gboolean egg_keyring1_verify_mac (GBytes *key, const guint8 *value, gsize n_value, const guint8 *data) { guint8 buffer[MAC_SIZE]; guint8 status = 0; gsize i; if (!egg_keyring1_calculate_mac (key, value, n_value, buffer)) { return FALSE; } for (i = 0; i < MAC_SIZE; i++) { status |= data[i] ^ buffer[i]; } return status == 0; } gboolean egg_keyring1_decrypt (GBytes *key, guint8 *data, gsize n_data) { gcry_cipher_hd_t hd; gcry_error_t gcry; gconstpointer secret; gsize n_secret; gboolean ret = FALSE; gcry = gcry_cipher_open (&hd, CIPHER_ALGO, GCRY_CIPHER_MODE_CBC, 0); if (gcry != 0) goto out; secret = g_bytes_get_data (key, &n_secret); gcry = gcry_cipher_setkey (hd, secret, n_secret); if (gcry != 0) goto out; gcry = gcry_cipher_setiv (hd, data + n_data, IV_SIZE); if (gcry != 0) goto out; gcry = gcry_cipher_decrypt (hd, data, n_data, NULL, 0); if (gcry != 0) goto out; ret = TRUE; out: gcry_cipher_close (hd); return ret; } gboolean egg_keyring1_encrypt (GBytes *key, guint8 *data, gsize n_data) { gcry_cipher_hd_t hd; gcry_error_t gcry; gconstpointer secret; gsize n_secret; gboolean ret = FALSE; gcry = gcry_cipher_open (&hd, CIPHER_ALGO, GCRY_CIPHER_MODE_CBC, 0); if (gcry != 0) goto out; secret = g_bytes_get_data (key, &n_secret); gcry = gcry_cipher_setkey (hd, secret, n_secret); if (gcry != 0) goto out; egg_keyring1_create_nonce (data + n_data, IV_SIZE); gcry = gcry_cipher_setiv (hd, data + n_data, IV_SIZE); if (gcry != 0) goto out; gcry = gcry_cipher_encrypt (hd, data, n_data, NULL, 0); if (gcry != 0) goto out; ret = TRUE; out: gcry_cipher_close (hd); return ret; } 07070100000033000081A400000000000000000000000167D9F0D900000694000000000000000000000000000000000000002400000000libsecret-0.21.7/egg/egg-keyring1.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #ifndef EGG_KEYRING1_H_ #define EGG_KEYRING1_H_ #include #define SALT_SIZE 32 #define ITERATION_COUNT 100000 #define MAC_SIZE 32 #define CIPHER_BLOCK_SIZE 16 #define KEY_SIZE 16 #define IV_SIZE CIPHER_BLOCK_SIZE void egg_keyring1_create_nonce (guint8 *nonce, gsize nonce_size); GBytes *egg_keyring1_derive_key (const char *password, gsize n_password, GBytes *salt, guint32 iteration_count); gboolean egg_keyring1_calculate_mac (GBytes *key, const guint8 *value, gsize n_value, guint8 *buffer); gboolean egg_keyring1_verify_mac (GBytes *key, const guint8 *value, gsize n_value, const guint8 *data); gboolean egg_keyring1_decrypt (GBytes *key, guint8 *data, gsize n_data); gboolean egg_keyring1_encrypt (GBytes *key, guint8 *data, gsize n_data); #endif /* EGG_KEYRING1_H_ */ 07070100000034000081A400000000000000000000000167D9F0D900000AD3000000000000000000000000000000000000002500000000libsecret-0.21.7/egg/egg-libgcrypt.c/* * gnome-keyring * * Copyright (C) 2008 Stefan Walter * * 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 * * Author: Stef Walter */ #include "config.h" #include "egg-libgcrypt.h" #include "egg-secure-memory.h" #include #include #include EGG_SECURE_DECLARE (libgcrypt); static void log_handler (gpointer unused, int unknown, const gchar *msg, va_list va) { /* TODO: Figure out additional arguments */ g_logv ("gcrypt", G_LOG_LEVEL_MESSAGE, msg, va); } static int no_mem_handler (gpointer unused, size_t sz, unsigned int unknown) { /* TODO: Figure out additional arguments */ g_error ("couldn't allocate %lu bytes of memory", (unsigned long int)sz); return 0; } static void fatal_handler (gpointer unused, int unknown, const gchar *msg) { /* TODO: Figure out additional arguments */ g_log ("gcrypt", G_LOG_LEVEL_ERROR, "%s", msg); } #if GCRYPT_VERSION_NUMBER < 0x010600 GCRY_THREAD_OPTION_PTHREAD_IMPL; #endif void egg_libgcrypt_initialize (void) { static size_t gcrypt_initialized = 0; unsigned seed; if (g_once_init_enter (&gcrypt_initialized)) { /* Only initialize libgcrypt if it hasn't already been initialized */ if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { #if GCRYPT_VERSION_NUMBER < 0x010600 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); #endif gcry_check_version (LIBGCRYPT_VERSION); gcry_set_log_handler (log_handler, NULL); gcry_set_outofcore_handler (no_mem_handler, NULL); gcry_set_fatalerror_handler (fatal_handler, NULL); gcry_set_allocation_handler ((gcry_handler_alloc_t)g_malloc, (gcry_handler_alloc_t)egg_secure_alloc, egg_secure_check, (gcry_handler_realloc_t)egg_secure_realloc, egg_secure_free); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); } gcry_create_nonce (&seed, sizeof (seed)); srand (seed); g_once_init_leave (&gcrypt_initialized, 1); } } 07070100000035000081A400000000000000000000000167D9F0D90000040F000000000000000000000000000000000000002500000000libsecret-0.21.7/egg/egg-libgcrypt.h/* * gnome-keyring * * Copyright (C) 2008 Stefan Walter * * 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 * * Author: Stef Walter */ #ifndef EGG_LIBGCRYPT_H_ #define EGG_LIBGCRYPT_H_ /* Initializes libgcrypt for use in a glib program */ void egg_libgcrypt_initialize (void); #endif /* EGG_LIBGCRYPT_H_ */ 07070100000036000081A400000000000000000000000167D9F0D900007B5A000000000000000000000000000000000000002900000000libsecret-0.21.7/egg/egg-secure-memory.c/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* egg-secure-memory.h - library for allocating memory that is non-pageable Copyright (C) 2007 Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, see . Author: Stef Walter */ /* * IMPORTANT: This is pure vanila standard C, no glib. We need this * because certain consumers of this protocol need to be built * without linking in any special libraries. ie: the PKCS#11 module. */ #include "config.h" #include "egg-secure-memory.h" #include #include #include #include #include #include #include #include #include #ifdef WITH_VALGRIND #include #include #endif #define DEBUG_SECURE_MEMORY 0 #if DEBUG_SECURE_MEMORY #define DEBUG_ALLOC(msg, n) fprintf(stderr, "%s %lu bytes\n", msg, n); #else #define DEBUG_ALLOC(msg, n) #endif #define DEFAULT_BLOCK_SIZE 16384 /* Use our own assert to guarantee no glib allocations */ #ifndef ASSERT #ifdef G_DISABLE_ASSERT #define ASSERT(x) #else #define ASSERT(x) assert(x) #endif #endif #define DO_LOCK() \ EGG_SECURE_GLOBALS.lock (); #define DO_UNLOCK() \ EGG_SECURE_GLOBALS.unlock (); static int show_warning = 1; int egg_secure_warnings = 1; /* * We allocate all memory in units of sizeof(void*). This * is our definition of 'word'. */ typedef void* word_t; /* The amount of extra words we can allocate */ #define WASTE 4 /* * Track allocated memory or a free block. This structure is not stored * in the secure memory area. It is allocated from a pool of other * memory. See meta_pool_xxx (). */ typedef struct _Cell { word_t *words; /* Pointer to secure memory */ size_t n_words; /* Amount of secure memory in words */ size_t requested; /* Amount actually requested by app, in bytes, 0 if unused */ const char *tag; /* Tag which describes the allocation */ struct _Cell *next; /* Next in memory ring */ struct _Cell *prev; /* Previous in memory ring */ } Cell; /* * A block of secure memory. This structure is the header in that block. */ typedef struct _Block { word_t *words; /* Actual memory hangs off here */ size_t n_words; /* Number of words in block */ size_t n_used; /* Number of used allocations */ struct _Cell* used_cells; /* Ring of used allocations */ struct _Cell* unused_cells; /* Ring of unused allocations */ struct _Block *next; /* Next block in list */ } Block; /* ----------------------------------------------------------------------------- * UNUSED STACK */ static inline void unused_push (void **stack, void *ptr) { ASSERT (ptr); ASSERT (stack); *((void**)ptr) = *stack; *stack = ptr; } static inline void* unused_pop (void **stack) { void *ptr; ASSERT (stack); ptr = *stack; *stack = *(void**)ptr; return ptr; } static inline void* unused_peek (void **stack) { ASSERT (stack); return *stack; } /* ----------------------------------------------------------------------------- * POOL META DATA ALLOCATION * * A pool for memory meta data. We allocate fixed size blocks. There are actually * two different structures stored in this pool: Cell and Block. Cell is allocated * way more often, and is bigger so we just allocate that size for both. */ /* Pool allocates this data type */ typedef union _Item { Cell cell; Block block; } Item; typedef struct _Pool { struct _Pool *next; /* Next pool in list */ size_t length; /* Length in bytes of the pool */ size_t used; /* Number of cells used in pool */ void *unused; /* Unused stack of unused stuff */ size_t n_items; /* Total number of items in pool */ Item items[1]; /* Actual items hang off here */ } Pool; static void * pool_alloc (void) { Pool *pool; void *pages, *item; size_t len, i; if (!EGG_SECURE_GLOBALS.pool_version || strcmp (EGG_SECURE_GLOBALS.pool_version, EGG_SECURE_POOL_VER_STR) != 0) { if (show_warning && egg_secure_warnings) fprintf (stderr, "the secure memory pool version does not match the code '%s' != '%s'\n", EGG_SECURE_GLOBALS.pool_version ? EGG_SECURE_GLOBALS.pool_version : "(null)", EGG_SECURE_POOL_VER_STR); show_warning = 0; return NULL; } /* A pool with an available item */ for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) { if (unused_peek (&pool->unused)) break; } /* Create a new pool */ if (pool == NULL) { len = getpagesize () * 2; pages = mmap (0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (pages == MAP_FAILED) return NULL; /* Fill in the block header, and inlude in block list */ pool = pages; pool->next = EGG_SECURE_GLOBALS.pool_data; EGG_SECURE_GLOBALS.pool_data = pool; pool->length = len; pool->used = 0; pool->unused = NULL; /* Fill block with unused items */ pool->n_items = (len - sizeof (Pool)) / sizeof (Item); for (i = 0; i < pool->n_items; ++i) unused_push (&pool->unused, pool->items + i); #ifdef WITH_VALGRIND VALGRIND_CREATE_MEMPOOL(pool, 0, 0); #endif } ++pool->used; ASSERT (unused_peek (&pool->unused)); item = unused_pop (&pool->unused); #ifdef WITH_VALGRIND VALGRIND_MEMPOOL_ALLOC (pool, item, sizeof (Item)); #endif return memset (item, 0, sizeof (Item)); } static void pool_free (void* item) { Pool *pool, **at; char *ptr, *beg, *end; ptr = item; /* Find which block this one belongs to */ for (at = (Pool **)&EGG_SECURE_GLOBALS.pool_data, pool = *at; pool != NULL; at = &pool->next, pool = *at) { beg = (char*)pool->items; end = (char*)pool + pool->length - sizeof (Item); if (ptr >= beg && ptr <= end) { ASSERT ((ptr - beg) % sizeof (Item) == 0); break; } } /* Otherwise invalid meta */ ASSERT (at); ASSERT (pool); ASSERT (pool->used > 0); /* No more meta cells used in this block, remove from list, destroy */ if (pool->used == 1) { *at = pool->next; #ifdef WITH_VALGRIND VALGRIND_DESTROY_MEMPOOL (pool); #endif munmap (pool, pool->length); return; } #ifdef WITH_VALGRIND VALGRIND_MEMPOOL_FREE (pool, item); VALGRIND_MAKE_MEM_UNDEFINED (item, sizeof (Item)); #endif --pool->used; memset (item, 0xCD, sizeof (Item)); unused_push (&pool->unused, item); } #ifndef G_DISABLE_ASSERT static int pool_valid (void* item) { Pool *pool; char *ptr, *beg, *end; ptr = item; /* Find which block this one belongs to */ for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) { beg = (char*)pool->items; end = (char*)pool + pool->length - sizeof (Item); if (ptr >= beg && ptr <= end) return (pool->used && (ptr - beg) % sizeof (Item) == 0); } return 0; } #endif /* G_DISABLE_ASSERT */ /* ----------------------------------------------------------------------------- * SEC ALLOCATION * * Each memory cell begins and ends with a pointer to its metadata. These are also * used as guards or red zones. Since they're treated as redzones by valgrind we * have to jump through a few hoops before reading and/or writing them. */ static inline size_t sec_size_to_words (size_t length) { return (length % sizeof (void*) ? 1 : 0) + (length / sizeof (void*)); } static inline void sec_write_guards (Cell *cell) { #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED (cell->words, sizeof (word_t)); VALGRIND_MAKE_MEM_UNDEFINED (cell->words + cell->n_words - 1, sizeof (word_t)); #endif ((void**)cell->words)[0] = (void*)cell; ((void**)cell->words)[cell->n_words - 1] = (void*)cell; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (cell->words, sizeof (word_t)); VALGRIND_MAKE_MEM_NOACCESS (cell->words + cell->n_words - 1, sizeof (word_t)); #endif } static inline void sec_check_guards (Cell *cell) { #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (cell->words, sizeof (word_t)); VALGRIND_MAKE_MEM_DEFINED (cell->words + cell->n_words - 1, sizeof (word_t)); #endif ASSERT(((void**)cell->words)[0] == (void*)cell); ASSERT(((void**)cell->words)[cell->n_words - 1] == (void*)cell); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (cell->words, sizeof (word_t)); VALGRIND_MAKE_MEM_NOACCESS (cell->words + cell->n_words - 1, sizeof (word_t)); #endif } static void sec_insert_cell_ring (Cell **ring, Cell *cell) { ASSERT (ring); ASSERT (cell); ASSERT (cell != *ring); ASSERT (cell->next == NULL); ASSERT (cell->prev == NULL); /* Insert back into the mix of available memory */ if (*ring) { cell->next = (*ring)->next; cell->prev = *ring; cell->next->prev = cell; cell->prev->next = cell; } else { cell->next = cell; cell->prev = cell; } *ring = cell; ASSERT (cell->next->prev == cell); ASSERT (cell->prev->next == cell); } static void sec_remove_cell_ring (Cell **ring, Cell *cell) { ASSERT (ring); ASSERT (*ring); ASSERT (cell->next); ASSERT (cell->prev); ASSERT (cell->next->prev == cell); ASSERT (cell->prev->next == cell); if (cell == *ring) { /* The last meta? */ if (cell->next == cell) { ASSERT (cell->prev == cell); *ring = NULL; /* Just pointing to this meta */ } else { ASSERT (cell->prev != cell); *ring = cell->next; } } cell->next->prev = cell->prev; cell->prev->next = cell->next; cell->next = cell->prev = NULL; ASSERT (*ring != cell); } static inline void* sec_cell_to_memory (Cell *cell) { return cell->words + 1; } static inline int sec_is_valid_word (Block *block, word_t *word) { return (word >= block->words && word < block->words + block->n_words); } static inline void sec_clear_undefined (void *memory, size_t from, size_t to) { char *ptr = memory; ASSERT (from <= to); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from); #endif memset (ptr + from, 0, to - from); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from); #endif } static inline void sec_clear_noaccess (void *memory, size_t from, size_t to) { char *ptr = memory; ASSERT (from <= to); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from); #endif memset (ptr + from, 0, to - from); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (ptr + from, to - from); #endif } static Cell* sec_neighbor_before (Block *block, Cell *cell) { word_t *word; ASSERT (cell); ASSERT (block); word = cell->words - 1; if (!sec_is_valid_word (block, word)) return NULL; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif cell = *word; sec_check_guards (cell); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t)); #endif return cell; } static Cell* sec_neighbor_after (Block *block, Cell *cell) { word_t *word; ASSERT (cell); ASSERT (block); word = cell->words + cell->n_words; if (!sec_is_valid_word (block, word)) return NULL; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif cell = *word; sec_check_guards (cell); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t)); #endif return cell; } static void* sec_alloc (Block *block, const char *tag, size_t length) { Cell *cell, *other; size_t n_words; void *memory; ASSERT (block); ASSERT (length); ASSERT (tag); if (!block->unused_cells) return NULL; /* * Each memory allocation is aligned to a pointer size, and * then, sandwidched between two pointers to its meta data. * These pointers also act as guards. * * We allocate memory in units of sizeof (void*) */ n_words = sec_size_to_words (length) + 2; /* Look for a cell of at least our required size */ cell = block->unused_cells; while (cell->n_words < n_words) { cell = cell->next; if (cell == block->unused_cells) { cell = NULL; break; } } if (!cell) return NULL; ASSERT (cell->tag == NULL); ASSERT (cell->requested == 0); ASSERT (cell->prev); ASSERT (cell->words); sec_check_guards (cell); /* Steal from the cell if it's too long */ if (cell->n_words > n_words + WASTE) { other = pool_alloc (); if (!other) return NULL; other->n_words = n_words; other->words = cell->words; cell->n_words -= n_words; cell->words += n_words; sec_write_guards (other); sec_write_guards (cell); cell = other; } if (cell->next) sec_remove_cell_ring (&block->unused_cells, cell); ++block->n_used; cell->tag = tag; cell->requested = length; sec_insert_cell_ring (&block->used_cells, cell); memory = sec_cell_to_memory (cell); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED (memory, length); #endif return memset (memory, 0, length); } static void* sec_free (Block *block, void *memory) { Cell *cell, *other; word_t *word; ASSERT (block); ASSERT (memory); word = memory; --word; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif /* Lookup the meta for this memory block (using guard pointer) */ ASSERT (sec_is_valid_word (block, word)); ASSERT (pool_valid (*word)); cell = *word; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (cell->words, cell->n_words * sizeof (word_t)); #endif sec_check_guards (cell); sec_clear_noaccess (memory, 0, cell->requested); sec_check_guards (cell); ASSERT (cell->requested > 0); ASSERT (cell->tag != NULL); /* Remove from the used cell ring */ sec_remove_cell_ring (&block->used_cells, cell); /* Find previous unallocated neighbor, and merge if possible */ other = sec_neighbor_before (block, cell); if (other && other->requested == 0) { ASSERT (other->tag == NULL); ASSERT (other->next && other->prev); other->n_words += cell->n_words; sec_write_guards (other); pool_free (cell); cell = other; } /* Find next unallocated neighbor, and merge if possible */ other = sec_neighbor_after (block, cell); if (other && other->requested == 0) { ASSERT (other->tag == NULL); ASSERT (other->next && other->prev); other->n_words += cell->n_words; other->words = cell->words; if (cell->next) sec_remove_cell_ring (&block->unused_cells, cell); sec_write_guards (other); pool_free (cell); cell = other; } /* Add to the unused list if not already there */ if (!cell->next) sec_insert_cell_ring (&block->unused_cells, cell); cell->tag = NULL; cell->requested = 0; --block->n_used; return NULL; } static void memcpy_with_vbits (void *dest, void *src, size_t length) { #ifdef WITH_VALGRIND int vbits_setup = 0; void *vbits = NULL; if (RUNNING_ON_VALGRIND) { vbits = malloc (length); if (vbits != NULL) vbits_setup = VALGRIND_GET_VBITS (src, vbits, length); VALGRIND_MAKE_MEM_DEFINED (src, length); } #endif memcpy (dest, src, length); #ifdef WITH_VALGRIND if (vbits_setup == 1) { (void)VALGRIND_SET_VBITS (dest, vbits, length); (void)VALGRIND_SET_VBITS (src, vbits, length); } free (vbits); #endif } static void* sec_realloc (Block *block, const char *tag, void *memory, size_t length) { Cell *cell, *other; word_t *word; size_t n_words; size_t valid; void *alloc; /* Standard realloc behavior, should have been handled elsewhere */ ASSERT (memory != NULL); ASSERT (length > 0); ASSERT (tag != NULL); /* Dig out where the meta should be */ word = memory; --word; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif ASSERT (sec_is_valid_word (block, word)); ASSERT (pool_valid (*word)); cell = *word; /* Validate that it's actually for real */ sec_check_guards (cell); ASSERT (cell->requested > 0); ASSERT (cell->tag != NULL); /* The amount of valid data */ valid = cell->requested; /* How many words we actually want */ n_words = sec_size_to_words (length) + 2; /* Less memory is required than is in the cell */ if (n_words <= cell->n_words) { /* TODO: No shrinking behavior yet */ cell->requested = length; alloc = sec_cell_to_memory (cell); /* * Even though we may be reusing the same cell, that doesn't * mean that the allocation is shrinking. It could have shrunk * and is now expanding back some. */ if (length < valid) sec_clear_undefined (alloc, length, valid); return alloc; } /* Need braaaaaiiiiiinsss... */ while (cell->n_words < n_words) { /* See if we have a neighbor who can give us some memory */ other = sec_neighbor_after (block, cell); if (!other || other->requested != 0) break; /* Eat the whole neighbor if not too big */ if (n_words - cell->n_words + WASTE >= other->n_words) { cell->n_words += other->n_words; sec_write_guards (cell); sec_remove_cell_ring (&block->unused_cells, other); pool_free (other); /* Steal from the neighbor */ } else { other->words += n_words - cell->n_words; other->n_words -= n_words - cell->n_words; sec_write_guards (other); cell->n_words = n_words; sec_write_guards (cell); } } if (cell->n_words >= n_words) { cell->requested = length; cell->tag = tag; alloc = sec_cell_to_memory (cell); sec_clear_undefined (alloc, valid, length); return alloc; } /* That didn't work, try alloc/free */ alloc = sec_alloc (block, tag, length); if (alloc) { memcpy_with_vbits (alloc, memory, valid); sec_free (block, memory); } return alloc; } static size_t sec_allocated (Block *block, void *memory) { Cell *cell; word_t *word; ASSERT (block); ASSERT (memory); word = memory; --word; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif /* Lookup the meta for this memory block (using guard pointer) */ ASSERT (sec_is_valid_word (block, word)); ASSERT (pool_valid (*word)); cell = *word; sec_check_guards (cell); ASSERT (cell->requested > 0); ASSERT (cell->tag != NULL); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t)); #endif return cell->requested; } static void sec_validate (Block *block) { Cell *cell; word_t *word, *last; #ifdef WITH_VALGRIND if (RUNNING_ON_VALGRIND) return; #endif word = block->words; last = word + block->n_words; for (;;) { ASSERT (word < last); ASSERT (sec_is_valid_word (block, word)); ASSERT (pool_valid (*word)); cell = *word; /* Validate that it's actually for real */ sec_check_guards (cell); /* Is it an allocated block? */ if (cell->requested > 0) { ASSERT (cell->tag != NULL); ASSERT (cell->next != NULL); ASSERT (cell->prev != NULL); ASSERT (cell->next->prev == cell); ASSERT (cell->prev->next == cell); ASSERT (cell->requested <= (cell->n_words - 2) * sizeof (word_t)); /* An unused block */ } else { ASSERT (cell->tag == NULL); ASSERT (cell->next != NULL); ASSERT (cell->prev != NULL); ASSERT (cell->next->prev == cell); ASSERT (cell->prev->next == cell); } word += cell->n_words; if (word == last) break; } } /* ----------------------------------------------------------------------------- * LOCKED MEMORY */ static void* sec_acquire_pages (size_t *sz, const char *during_tag) { void *pages; unsigned long pgsize; ASSERT (sz); ASSERT (*sz); ASSERT (during_tag); /* Make sure sz is a multiple of the page size */ pgsize = getpagesize (); *sz = (*sz + pgsize -1) & ~(pgsize - 1); #if defined(HAVE_MLOCK) pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (pages == MAP_FAILED) { if (show_warning && egg_secure_warnings) fprintf (stderr, "couldn't map %lu bytes of memory (%s): %s\n", (unsigned long)*sz, during_tag, strerror (errno)); show_warning = 0; return NULL; } if (mlock (pages, *sz) < 0) { if (show_warning && egg_secure_warnings && errno != EPERM) { fprintf (stderr, "couldn't lock %lu bytes of memory (%s): %s\n", (unsigned long)*sz, during_tag, strerror (errno)); show_warning = 0; } munmap (pages, *sz); return NULL; } DEBUG_ALLOC ("gkr-secure-memory: new block ", *sz); #if defined(MADV_DONTDUMP) if (madvise (pages, *sz, MADV_DONTDUMP) < 0) { if (show_warning && egg_secure_warnings) { /* * Not fatal - this was added in Linux 3.4 and older * kernels will legitimately fail this at runtime */ fprintf (stderr, "couldn't MADV_DONTDUMP %lu bytes of memory (%s): %s\n", (unsigned long)*sz, during_tag, strerror (errno)); } } #endif show_warning = 1; return pages; #else if (show_warning && egg_secure_warnings) fprintf (stderr, "your system does not support private memory"); show_warning = 0; return NULL; #endif } static void sec_release_pages (void *pages, size_t sz) { ASSERT (pages); ASSERT (sz % getpagesize () == 0); #if defined(HAVE_MLOCK) if (munlock (pages, sz) < 0 && egg_secure_warnings) fprintf (stderr, "couldn't unlock private memory: %s\n", strerror (errno)); if (munmap (pages, sz) < 0 && egg_secure_warnings) fprintf (stderr, "couldn't unmap private anonymous memory: %s\n", strerror (errno)); DEBUG_ALLOC ("gkr-secure-memory: freed block ", sz); #else ASSERT (FALSE); #endif } /* ----------------------------------------------------------------------------- * MANAGE DIFFERENT BLOCKS */ static Block *all_blocks = NULL; static Block* sec_block_create (size_t size, const char *during_tag) { Block *block; Cell *cell; ASSERT (during_tag); /* We can force all all memory to be malloced */ if (getenv ("SECMEM_FORCE_FALLBACK")) return NULL; block = pool_alloc (); if (!block) return NULL; cell = pool_alloc (); if (!cell) { pool_free (block); return NULL; } /* The size above is a minimum, we're free to go bigger */ if (size < DEFAULT_BLOCK_SIZE) size = DEFAULT_BLOCK_SIZE; block->words = sec_acquire_pages (&size, during_tag); block->n_words = size / sizeof (word_t); if (!block->words) { pool_free (block); pool_free (cell); return NULL; } #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (block->words, size); #endif /* The first cell to allocate from */ cell->words = block->words; cell->n_words = block->n_words; cell->requested = 0; sec_write_guards (cell); sec_insert_cell_ring (&block->unused_cells, cell); block->next = all_blocks; all_blocks = block; return block; } static void sec_block_destroy (Block *block) { Block *bl, **at; Cell *cell; ASSERT (block); ASSERT (block->words); ASSERT (block->n_used == 0); /* Remove from the list */ for (at = &all_blocks, bl = *at; bl; at = &bl->next, bl = *at) { if (bl == block) { *at = block->next; break; } } /* Must have been found */ ASSERT (bl == block); ASSERT (block->used_cells == NULL); /* Release all the meta data cells */ while (block->unused_cells) { cell = block->unused_cells; sec_remove_cell_ring (&block->unused_cells, cell); pool_free (cell); } /* Release all pages of secure memory */ sec_release_pages (block->words, block->n_words * sizeof (word_t)); pool_free (block); } /* ------------------------------------------------------------------------ * PUBLIC FUNCTIONALITY */ void* egg_secure_alloc_full (const char *tag, size_t length, int flags) { Block *block; void *memory = NULL; if (tag == NULL) tag = "?"; if (length > 0xFFFFFFFF / 2) { if (egg_secure_warnings) fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", (unsigned long)length); return NULL; } /* Can't allocate zero bytes */ if (length == 0) return NULL; DO_LOCK (); for (block = all_blocks; block; block = block->next) { memory = sec_alloc (block, tag, length); if (memory) break; } /* None of the current blocks have space, allocate new */ if (!memory) { block = sec_block_create (length, tag); if (block) memory = sec_alloc (block, tag, length); } #ifdef WITH_VALGRIND if (memory != NULL) VALGRIND_MALLOCLIKE_BLOCK (memory, length, sizeof (void*), 1); #endif DO_UNLOCK (); if (!memory && (flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback != NULL) { memory = EGG_SECURE_GLOBALS.fallback (NULL, length); if (memory) /* Our returned memory is always zeroed */ memset (memory, 0, length); } if (!memory) errno = ENOMEM; return memory; } void* egg_secure_realloc_full (const char *tag, void *memory, size_t length, int flags) { Block *block = NULL; size_t previous = 0; int donew = 0; void *alloc = NULL; if (tag == NULL) tag = "?"; if (length > 0xFFFFFFFF / 2) { if (egg_secure_warnings) fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", (unsigned long)length); return NULL; } if (memory == NULL) return egg_secure_alloc_full (tag, length, flags); if (!length) { egg_secure_free_full (memory, flags); return NULL; } DO_LOCK (); /* Find out where it belongs to */ for (block = all_blocks; block; block = block->next) { if (sec_is_valid_word (block, memory)) { previous = sec_allocated (block, memory); #ifdef WITH_VALGRIND /* Let valgrind think we are unallocating so that it'll validate */ VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t)); #endif alloc = sec_realloc (block, tag, memory, length); #ifdef WITH_VALGRIND /* Now tell valgrind about either the new block or old one */ VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory, alloc ? length : previous, sizeof (word_t), 1); #endif break; } } /* If it didn't work we may need to allocate a new block */ if (block && !alloc) donew = 1; if (block && block->n_used == 0) sec_block_destroy (block); DO_UNLOCK (); if (!block) { if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) { /* * In this case we can't zero the returned memory, * because we don't know what the block size was. */ return EGG_SECURE_GLOBALS.fallback (memory, length); } else { if (egg_secure_warnings) fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n", (unsigned long)memory); ASSERT (0 && "memory does does not belong to secure memory pool"); return NULL; } } if (donew) { alloc = egg_secure_alloc_full (tag, length, flags); if (alloc) { memcpy_with_vbits (alloc, memory, previous); egg_secure_free_full (memory, flags); } } if (!alloc) errno = ENOMEM; return alloc; } void egg_secure_free (void *memory) { egg_secure_free_full (memory, EGG_SECURE_USE_FALLBACK); } void egg_secure_free_full (void *memory, int flags) { Block *block = NULL; if (memory == NULL) return; DO_LOCK (); /* Find out where it belongs to */ for (block = all_blocks; block; block = block->next) { if (sec_is_valid_word (block, memory)) break; } #ifdef WITH_VALGRIND /* We like valgrind's warnings, so give it a first whack at checking for errors */ if (block != NULL || !(flags & EGG_SECURE_USE_FALLBACK)) VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t)); #endif if (block != NULL) { sec_free (block, memory); if (block->n_used == 0) sec_block_destroy (block); } DO_UNLOCK (); if (!block) { if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) { EGG_SECURE_GLOBALS.fallback (memory, 0); } else { if (egg_secure_warnings) fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n", (unsigned long)memory); ASSERT (0 && "memory does does not belong to secure memory pool"); } } } int egg_secure_check (const void *memory) { Block *block = NULL; DO_LOCK (); /* Find out where it belongs to */ for (block = all_blocks; block; block = block->next) { if (sec_is_valid_word (block, (word_t*)memory)) break; } DO_UNLOCK (); return block == NULL ? 0 : 1; } void egg_secure_validate (void) { Block *block = NULL; DO_LOCK (); for (block = all_blocks; block; block = block->next) sec_validate (block); DO_UNLOCK (); } static egg_secure_rec * records_for_ring (Cell *cell_ring, egg_secure_rec *records, unsigned int *count, unsigned int *total) { egg_secure_rec *new_rec; unsigned int allocated = *count; Cell *cell; cell = cell_ring; do { if (*count >= allocated) { new_rec = realloc (records, sizeof (egg_secure_rec) * (allocated + 32)); if (new_rec == NULL) { *count = 0; free (records); return NULL; } else { records = new_rec; allocated += 32; } } if (cell != NULL) { records[*count].request_length = cell->requested; records[*count].block_length = cell->n_words * sizeof (word_t); records[*count].tag = cell->tag; (*count)++; (*total) += cell->n_words; cell = cell->next; } } while (cell != NULL && cell != cell_ring); return records; } egg_secure_rec * egg_secure_records (unsigned int *count) { egg_secure_rec *records = NULL; Block *block = NULL; unsigned int total; *count = 0; DO_LOCK (); for (block = all_blocks; block != NULL; block = block->next) { total = 0; records = records_for_ring (block->unused_cells, records, count, &total); if (records == NULL) break; records = records_for_ring (block->used_cells, records, count, &total); if (records == NULL) break; /* Make sure this actually accounts for all memory */ ASSERT (total == block->n_words); } DO_UNLOCK (); return records; } char* egg_secure_strdup_full (const char *tag, const char *str, int options) { size_t len; char *res; if (!str) return NULL; len = strlen (str) + 1; res = (char *)egg_secure_alloc_full (tag, len, options); strcpy (res, str); return res; } char * egg_secure_strndup_full (const char *tag, const char *str, size_t length, int options) { size_t len; char *res; const char *end; if (!str) return NULL; end = memchr (str, '\0', length); if (end != NULL) length = (end - str); len = length + 1; res = (char *)egg_secure_alloc_full (tag, len, options); memcpy (res, str, len); res[length] = '\0'; return res; } void egg_secure_clear (void *p, size_t length) { volatile char *vp; if (p == NULL) return; vp = (volatile char*)p; while (length) { *vp = 0xAA; vp++; length--; } } void egg_secure_strclear (char *str) { if (!str) return; egg_secure_clear ((unsigned char*)str, strlen (str)); } void egg_secure_strfree (char *str) { /* * If we're using unpageable 'secure' memory, then the free call * should zero out the memory, but because on certain platforms * we may be using normal memory, zero it out here just in case. */ egg_secure_strclear (str); egg_secure_free_full (str, EGG_SECURE_USE_FALLBACK); } 07070100000037000081A400000000000000000000000167D9F0D900001010000000000000000000000000000000000000002900000000libsecret-0.21.7/egg/egg-secure-memory.h/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* egg-secure-memory.h - library for allocating memory that is non-pageable Copyright (C) 2007 Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, see . Author: Stef Walter */ #ifndef EGG_SECURE_MEMORY_H #define EGG_SECURE_MEMORY_H #include #include /* ------------------------------------------------------------------- * Low Level Secure Memory * * IMPORTANT: This is pure vanila standard C, no glib. We need this * because certain consumers of this protocol need to be built * without linking in any special libraries. ie: the PKCS#11 module. * * Thread locking * * In order to use these functions in a module the following functions * must be defined somewhere, and provide appropriate locking for * secure memory between threads: */ typedef struct { void (* lock) (void); void (* unlock) (void); void * (* fallback) (void *pointer, size_t length); void * pool_data; const char * pool_version; } egg_secure_glob; #define EGG_SECURE_POOL_VER_STR "1.0" #define EGG_SECURE_GLOBALS SECMEM_pool_data_v1_0 #define EGG_SECURE_DEFINE_GLOBALS(lock, unlock, fallback) \ egg_secure_glob EGG_SECURE_GLOBALS = { \ lock, unlock, fallback, NULL, EGG_SECURE_POOL_VER_STR }; #define EGG_SECURE_DEFINE_GLIB_GLOBALS() \ static GMutex memory_mutex = { NULL, }; \ static void egg_memory_lock (void) \ { g_mutex_lock (&memory_mutex); } \ static void egg_memory_unlock (void) \ { g_mutex_unlock (&memory_mutex); } \ EGG_SECURE_DEFINE_GLOBALS (egg_memory_lock, egg_memory_unlock, g_realloc); extern egg_secure_glob EGG_SECURE_GLOBALS; /* * Main functionality * * Allocations return NULL on failure. */ #define EGG_SECURE_USE_FALLBACK 0x0001 #define EGG_SECURE_DECLARE(tag) \ static inline void* egg_secure_alloc (size_t length) { \ return egg_secure_alloc_full (G_STRINGIFY (tag), length, EGG_SECURE_USE_FALLBACK); \ } \ static inline void* egg_secure_realloc (void *p, size_t length) { \ return egg_secure_realloc_full (G_STRINGIFY (tag), p, length, EGG_SECURE_USE_FALLBACK); \ } \ static inline void* egg_secure_strdup (const char *str) { \ return egg_secure_strdup_full (G_STRINGIFY (tag), str, EGG_SECURE_USE_FALLBACK); \ } \ static inline void* egg_secure_strndup (const char *str, size_t length) { \ return egg_secure_strndup_full (G_STRINGIFY (tag), str, length, EGG_SECURE_USE_FALLBACK); \ } void* egg_secure_alloc_full (const char *tag, size_t length, int options); void* egg_secure_realloc_full (const char *tag, void *p, size_t length, int options); void egg_secure_free (void* p); void egg_secure_free_full (void* p, int fallback); void egg_secure_clear (void *p, size_t length); int egg_secure_check (const void* p); void egg_secure_validate (void); char* egg_secure_strdup_full (const char *tag, const char *str, int options); char* egg_secure_strndup_full (const char *tag, const char *str, size_t length, int options); void egg_secure_strclear (char *str); void egg_secure_strfree (char *str); typedef struct { const char *tag; size_t request_length; size_t block_length; } egg_secure_rec; egg_secure_rec * egg_secure_records (unsigned int *count); #endif /* EGG_SECURE_MEMORY_H */ 07070100000038000081A400000000000000000000000167D9F0D9000015FB000000000000000000000000000000000000002300000000libsecret-0.21.7/egg/egg-testing.c/* * gnome-keyring * * Copyright (C) 2011 Collabora Ltd. * * 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 * * Author: Stef Walter */ #include "config.h" #include "egg-testing.h" #include #include #include #include #include #include static const char HEXC[] = "0123456789ABCDEF"; gchar * egg_test_escape_data (const guchar *data, gsize n_data) { GString *result; gchar c; gsize i; guchar j; g_assert_nonnull (data); result = g_string_sized_new (n_data * 2 + 1); for (i = 0; i < n_data; ++i) { c = data[i]; if (g_ascii_isprint (c) && !strchr ("\n\r\v", c)) { g_string_append_c (result, c); } else { g_string_append (result, "\\x"); j = c >> 4 & 0xf; g_string_append_c (result, HEXC[j]); j = c & 0xf; g_string_append_c (result, HEXC[j]); } } return g_string_free (result, FALSE); } void egg_assertion_message_cmpmem (const char *domain, const char *file, int line, const char *func, const char *expr, gconstpointer arg1, gsize n_arg1, const char *cmp, gconstpointer arg2, gsize n_arg2) { char *a1, *a2, *s; a1 = arg1 ? egg_test_escape_data (arg1, n_arg1) : g_strdup ("NULL"); a2 = arg2 ? egg_test_escape_data (arg2, n_arg2) : g_strdup ("NULL"); s = g_strdup_printf ("assertion failed (%s): (%s %s %s)", expr, a1, cmp, a2); g_free (a1); g_free (a2); g_assertion_message (domain, file, line, func, s); g_free (s); } static void (*wait_stop_impl) (void); static gboolean (*wait_until_impl) (int timeout); void egg_test_wait_stop (void) { g_assert_nonnull (wait_stop_impl); (wait_stop_impl) (); } gboolean egg_test_wait_until (int timeout) { g_assert_nonnull (wait_until_impl); return (wait_until_impl) (timeout); } void egg_test_wait_idle (void) { GMainContext *context; g_assert_nonnull (wait_until_impl); context = g_main_context_get_thread_default (); while (g_main_context_iteration (context, FALSE)); } static GMainLoop *wait_loop = NULL; static void loop_wait_stop (void) { g_assert_nonnull (wait_loop); g_main_loop_quit (wait_loop); } static gboolean on_loop_wait_timeout (gpointer data) { gboolean *timed_out = data; *timed_out = TRUE; g_assert_nonnull (wait_loop); g_main_loop_quit (wait_loop); return TRUE; /* we remove this source later */ } static gboolean loop_wait_until (int timeout) { gboolean timed_out = FALSE; guint source; g_assert_null (wait_loop); wait_loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); source = g_timeout_add (timeout, on_loop_wait_timeout, &timed_out); g_main_loop_run (wait_loop); g_source_remove (source); g_main_loop_unref (wait_loop); wait_loop = NULL; return !timed_out; } gint egg_tests_run_with_loop (void) { gint ret; wait_stop_impl = loop_wait_stop; wait_until_impl = loop_wait_until; ret = g_test_run (); wait_stop_impl = NULL; wait_until_impl = NULL; while (g_main_context_iteration (NULL, FALSE)); return ret; } void egg_tests_copy_scratch_file (const gchar *directory, const gchar *filename) { GError *error = NULL; gchar *basename; gchar *contents; gchar *destination; gsize length; g_assert (directory); g_file_get_contents (filename, &contents, &length, &error); g_assert_no_error (error); basename = g_path_get_basename (filename); destination = g_build_filename (directory, basename, NULL); g_free (basename); g_file_set_contents (destination, contents, length, &error); g_assert_no_error (error); g_free (destination); g_free (contents); } gchar * egg_tests_create_scratch_directory (const gchar *file_to_copy, ...) { gchar *basename; gchar *directory; va_list va; basename = g_path_get_basename (g_get_prgname ()); directory = g_strdup_printf ("/tmp/scratch-%s.XXXXXX", basename); g_free (basename); if (!g_mkdtemp (directory)) g_assert_not_reached (); va_start (va, file_to_copy); while (file_to_copy != NULL) { egg_tests_copy_scratch_file (directory, file_to_copy); file_to_copy = va_arg (va, const gchar *); } va_end (va); return directory; } void egg_tests_remove_scratch_directory (const gchar *directory) { gchar *argv[] = { "rm", "-rf", (gchar *)directory, NULL }; GError *error = NULL; gint rm_status; g_assert_cmpstr (directory, !=, ""); g_assert_cmpstr (directory, !=, "/"); g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, &rm_status, &error); g_assert_no_error (error); g_assert_cmpint (rm_status, ==, 0); } 07070100000039000081A400000000000000000000000167D9F0D900000A8F000000000000000000000000000000000000002300000000libsecret-0.21.7/egg/egg-testing.h/* * gnome-keyring * * Copyright (C) 2011 Stefan Walter * * 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 * * Author: Stef Walter */ #ifndef EGG_TESTING_H_ #define EGG_TESTING_H_ #include #include #define egg_assert_cmpsize(a, o, b) \ g_assert_cmpuint ((guint)(a), o, (guint)(b)) #define egg_assert_cmpmem(a, na, cmp, b, nb) \ do { gconstpointer __p1 = (a), __p2 = (b); gsize __n1 = (na), __n2 = (nb); \ if (__n1 cmp __n2 && memcmp (__p1, __p2, __n1) cmp 0) ; else \ egg_assertion_message_cmpmem (G_LOG_DOMAIN, __FILE__, __LINE__, \ G_STRFUNC, #a "[" #na"] " #cmp " " #b "[" #nb "]", \ __p1, __n1, #cmp, __p2, __n2); } while (0) void egg_assertion_message_cmpmem (const char *domain, const char *file, int line, const char *func, const char *expr, gconstpointer arg1, gsize n_arg1, const char *cmp, gconstpointer arg2, gsize n_arg2); gchar * egg_test_escape_data (const guchar *data, gsize size); void egg_test_wait_stop (void); #define egg_test_wait() g_assert_true (egg_test_wait_until (20000)) gboolean egg_test_wait_until (int timeout); void egg_test_wait_idle (void); gint egg_tests_run_with_loop (void); void egg_tests_copy_scratch_file (const gchar *directory, const gchar *file_to_copy); gchar * egg_tests_create_scratch_directory (const gchar *file_to_copy, ...) G_GNUC_NULL_TERMINATED; void egg_tests_remove_scratch_directory (const gchar *directory); #endif /* EGG_TESTING_H_ */ 0707010000003A000081A400000000000000000000000167D9F0D900002B59000000000000000000000000000000000000002000000000libsecret-0.21.7/egg/egg-tpm2.c/* libsecret - TSS interface implementations for libsecret * * Copyright (C) 2021 Dhanuka Warusadura * * 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 * * Author: Dhanuka Warusadura */ #include "config.h" #include "egg-tpm2.h" #include #include #include #include #define MAX_BYTE_SIZE 64 struct EggTpm2Context { TSS2_TCTI_CONTEXT *tcti_context; ESYS_CONTEXT *esys_context; ESYS_TR primary_key; }; static gboolean egg_tpm2_generate_primary_key(EggTpm2Context *context, GError **error) { TSS2_RC ret; TPM2B_SENSITIVE_CREATE sensitive_params = { .size = 0, .sensitive = { .userAuth = { .size = 0, .buffer = {0}, }, .data = { .size = 0, .buffer = {0}, }, }, }; TPM2B_PUBLIC public_key_param = { .size = 0, .publicArea = { .type = TPM2_ALG_RSA, .nameAlg = TPM2_ALG_SHA256, .objectAttributes = ( TPMA_OBJECT_USERWITHAUTH | TPMA_OBJECT_RESTRICTED | TPMA_OBJECT_DECRYPT | TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT | TPMA_OBJECT_SENSITIVEDATAORIGIN), .authPolicy = { .size = 0, }, .parameters.rsaDetail = { .symmetric = { .algorithm = TPM2_ALG_AES, .keyBits.aes = 128, .mode.aes = TPM2_ALG_CFB }, .scheme = { .scheme = TPM2_ALG_NULL }, .keyBits = 2048, .exponent = 0, }, .unique.rsa = { .size = 0, .buffer = {}, }, }, }; TPM2B_DATA outside_info = { .size = 0, .buffer = {}, }; TPML_PCR_SELECTION pcrs = { .count = 0, }; TPM2B_PUBLIC *public; TPM2B_CREATION_DATA *creation_data; TPM2B_DIGEST *hash; TPMT_TK_CREATION *ticket; ret = Esys_CreatePrimary(context->esys_context, ESYS_TR_RH_OWNER, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &sensitive_params, &public_key_param, &outside_info, &pcrs, &context->primary_key, &public, &creation_data, &hash, &ticket); if (ret != TSS2_RC_SUCCESS) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Esys_CreatePrimary: %s", Tss2_RC_Decode(ret)); return FALSE; } Esys_Free(public); Esys_Free(creation_data); Esys_Free(hash); Esys_Free(ticket); return TRUE; } static GBytes * egg_tpm2_generate_random_data(EggTpm2Context *context, GError **error) { TSS2_RC ret; TPM2B_DIGEST *random_data; GBytes *bytes; ret = Esys_GetRandom(context->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, MAX_BYTE_SIZE, &random_data); if (ret != TSS2_RC_SUCCESS) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Esys_GetRandom: %s", Tss2_RC_Decode(ret)); return NULL; } bytes = g_bytes_new(random_data->buffer, random_data->size); Esys_Free(random_data); return bytes; } EggTpm2Context * egg_tpm2_initialize(GError **error) { TSS2_RC ret; EggTpm2Context *context; gsize n_context; const gchar *tcti_conf; gboolean status; n_context = 1; context = g_new(EggTpm2Context, n_context); tcti_conf = g_getenv("TCTI"); ret = Tss2_TctiLdr_Initialize(tcti_conf, &context->tcti_context); if (ret != TSS2_RC_SUCCESS) { egg_tpm2_finalize(context); g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Tss2_TctiLdr_Initialize: %s", Tss2_RC_Decode(ret)); return NULL; } ret = Esys_Initialize(&context->esys_context, context->tcti_context, NULL); if (ret != TSS2_RC_SUCCESS) { egg_tpm2_finalize(context); g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Esys_Initialize: %s", Tss2_RC_Decode(ret)); return NULL; } ret = Esys_Startup(context->esys_context, TPM2_SU_CLEAR); if (ret != TSS2_RC_SUCCESS) { egg_tpm2_finalize(context); g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Esys_Startup: %s", Tss2_RC_Decode(ret)); return NULL; } status = egg_tpm2_generate_primary_key(context, error); if (!status) { egg_tpm2_finalize(context); return NULL; } return context; } void egg_tpm2_finalize(EggTpm2Context *context) { if (context->esys_context) Esys_Finalize(&context->esys_context); if (context->tcti_context) Tss2_TctiLdr_Finalize(&context->tcti_context); g_free(context); } GBytes * egg_tpm2_generate_master_password(EggTpm2Context *context, GError **error) { TSS2_RC ret; TPM2B_PRIVATE *out_private; TPM2B_PUBLIC *out_public; TPM2B_CREATION_DATA *creation_data; TPM2B_DIGEST *hash; TPMT_TK_CREATION *ticket; gconstpointer data; gsize size; GBytes *input; GBytes *output; TPM2B_SENSITIVE_CREATE in_sensitive = { .size = 0, .sensitive = { .data = { .size = MAX_BYTE_SIZE } } }; TPM2B_PUBLIC in_public = { .size = 0, .publicArea = { .type = TPM2_ALG_KEYEDHASH, .nameAlg = TPM2_ALG_SHA256, .objectAttributes = ( TPMA_OBJECT_USERWITHAUTH | TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT), .authPolicy = { .size = 0, }, .parameters.keyedHashDetail = { .scheme = { .scheme = TPM2_ALG_NULL, .details = { .hmac = { .hashAlg = TPM2_ALG_SHA256 } } } }, .unique.keyedHash = { .size = 0, .buffer = {}, }, } }; TPM2B_DATA outside_info = { .size = 0, .buffer = {} }; TPML_PCR_SELECTION pcrs = { .count = 0 }; input = egg_tpm2_generate_random_data(context, error); if (!input) { g_bytes_unref(input); return NULL; } data = g_bytes_get_data(input, &size); if (size > sizeof(in_sensitive.sensitive.data.buffer)) { g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Input is too long"); return NULL; } memcpy(in_sensitive.sensitive.data.buffer, data, size); in_sensitive.sensitive.data.size = size; g_bytes_unref(input); ret = Esys_Create(context->esys_context, context->primary_key, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &in_sensitive, &in_public, &outside_info, &pcrs, &out_private, &out_public, &creation_data, &hash, &ticket); if (ret != TSS2_RC_SUCCESS) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Esys_Create: %s", Tss2_RC_Decode(ret)); return NULL; } gsize out_private_offset = 0; gsize out_public_offset = 0; GVariant *out_private_variant; GVariant *out_public_variant; GVariant *variant; guint8 marshaled_out_private[sizeof(*out_private)]; guint8 marshaled_out_public[sizeof(*out_public)]; ret = Tss2_MU_TPM2B_PRIVATE_Marshal(out_private, marshaled_out_private, sizeof(marshaled_out_private), &out_private_offset); if (ret != TSS2_RC_SUCCESS) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Tss2_MU_TPM2B_PRIVATE_Marshal: %s", Tss2_RC_Decode(ret)); return NULL; } out_private_variant = g_variant_new_fixed_array( G_VARIANT_TYPE_BYTE, marshaled_out_private, out_private_offset, sizeof(guint8)); ret = Tss2_MU_TPM2B_PUBLIC_Marshal(out_public, marshaled_out_public, sizeof(marshaled_out_public), &out_public_offset); if (ret != TSS2_RC_SUCCESS) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Tss2_MU_TPM2B_PUBLIC_Marshal: %s", Tss2_RC_Decode(ret)); return NULL; } out_public_variant = g_variant_new_fixed_array( G_VARIANT_TYPE_BYTE, marshaled_out_public, out_public_offset, sizeof(guint8)); variant = g_variant_new("(u@ayu@ay)", out_private_offset, out_private_variant, out_public_offset, out_public_variant); output = g_variant_get_data_as_bytes(variant); g_variant_unref(variant); Esys_Free(out_public); Esys_Free(out_private); Esys_Free(creation_data); Esys_Free(hash); Esys_Free(ticket); return output; } GBytes * egg_tpm2_decrypt_master_password(EggTpm2Context *context, GBytes *input, GError **error) { TSS2_RC ret; GBytes *output; TPM2B_SENSITIVE_DATA *out_data; GVariant *variant; gconstpointer data; gsize out_private_offset = 0; gsize out_public_offset = 0; gsize count = 0; gsize offset = 0; GVariant *out_private_variant; GVariant *out_public_variant; ESYS_TR out_key; variant = g_variant_new_from_bytes(G_VARIANT_TYPE( "(uayuay)"), input, TRUE); g_variant_get(variant, "(u@ayu@ay)", &out_private_offset, &out_private_variant, &out_public_offset, &out_public_variant); g_variant_unref(variant); data = g_variant_get_fixed_array(out_private_variant, &count, sizeof(guint8)); guint8 *marshaled_out_private = g_memdup2(data, count); count = 0; TPM2B_PRIVATE out_private = { .size = 0 }; ret = Tss2_MU_TPM2B_PRIVATE_Unmarshal(marshaled_out_private, out_private_offset, &offset, &out_private); g_variant_unref(out_private_variant); g_free(marshaled_out_private); if (ret != TSS2_RC_SUCCESS) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Tss2_MU_TPM2B_PRIVATE_Unmarshal: %s", Tss2_RC_Decode(ret)); return NULL; } offset = 0; data = g_variant_get_fixed_array(out_public_variant, &count, sizeof(guint8)); guint8 *marshaled_out_public = g_memdup2(data, count); TPM2B_PUBLIC out_public = { .size = 0 }; ret = Tss2_MU_TPM2B_PUBLIC_Unmarshal(marshaled_out_public, out_public_offset, &offset, &out_public); g_variant_unref(out_public_variant); g_free(marshaled_out_public); if (ret != TSS2_RC_SUCCESS) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Tss2_MU_TPM2B_PUBLIC_Unmarshal: %s", Tss2_RC_Decode(ret)); return NULL; } ret = Esys_Load(context->esys_context, context->primary_key, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &out_private, &out_public, &out_key); if (ret != TSS2_RC_SUCCESS) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Esys_Load: %s", Tss2_RC_Decode(ret)); return NULL; } ret = Esys_Unseal(context->esys_context, out_key, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &out_data); if (ret != TSS2_RC_SUCCESS) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Esys_Unseal: %s", Tss2_RC_Decode(ret)); return NULL; } output = g_bytes_new(out_data->buffer, out_data->size); Esys_Free(out_data); return output; } 0707010000003B000081A400000000000000000000000167D9F0D900000572000000000000000000000000000000000000002000000000libsecret-0.21.7/egg/egg-tpm2.h/* libsecret - TSS interface for libsecret * * Copyright (C) 2021 Dhanuka Warusadura * * 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 * * Author: Dhanuka Warusadura */ #ifndef EGG_TPM2_H_ #define EGG_TPM2_H_ #include #include typedef struct EggTpm2Context EggTpm2Context; EggTpm2Context *egg_tpm2_initialize (GError **); void egg_tpm2_finalize (EggTpm2Context *); GBytes *egg_tpm2_generate_master_password (EggTpm2Context *, GError **); GBytes *egg_tpm2_decrypt_master_password (EggTpm2Context *, GBytes *, GError **); #endif 0707010000003C000081A400000000000000000000000167D9F0D900001A24000000000000000000000000000000000000002C00000000libsecret-0.21.7/egg/egg-unix-credentials.c/* * Copyright (C) 2008 Stefan Walter * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * 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. * * The names of contributors to this software may not be * used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "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 * COPYRIGHT OWNER OR CONTRIBUTORS 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. * * Author: Stef Walter */ #include "config.h" #include "egg-unix-credentials.h" #include #include #include #include #include #include #include #if defined(HAVE_GETPEERUCRED) #include #endif int egg_unix_credentials_read (int sock, pid_t *pid, uid_t *uid) { struct msghdr msg; struct iovec iov; char buf; int ret; #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS) /* Prefer CMSGCRED over LOCAL_CREDS because the former provides the * remote PID. */ #if defined(HAVE_CMSGCRED) struct cmsgcred *cred; #else /* defined(LOCAL_CREDS) */ struct sockcred *cred; #endif union { struct cmsghdr hdr; char cred[CMSG_SPACE (sizeof *cred)]; } cmsg; #endif *pid = 0; *uid = 0; /* If LOCAL_CREDS are used in this platform, they have already been * initialized by init_connection prior to sending of the credentials * byte we receive below. */ iov.iov_base = &buf; iov.iov_len = 1; memset (&msg, 0, sizeof (msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS) memset (&cmsg, 0, sizeof (cmsg)); msg.msg_control = (caddr_t) &cmsg; msg.msg_controllen = CMSG_SPACE(sizeof *cred); #endif again: ret = recvmsg (sock, &msg, 0); if (ret < 0) { if (errno == EINTR) goto again; return -1; } else if (ret == 0) { /* Disconnected */ return -1; } if (buf != '\0') { fprintf (stderr, "credentials byte was not nul\n"); return -1; } #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS) if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof *cred) || cmsg.hdr.cmsg_type != SCM_CREDS) { fprintf (stderr, "message from recvmsg() was not SCM_CREDS\n"); return -1; } #endif { #ifdef SO_PEERCRED #ifndef __OpenBSD__ struct ucred cr; #else struct sockpeercred cr; #endif socklen_t cr_len = sizeof (cr); if (getsockopt (sock, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 && cr_len == sizeof (cr)) { *pid = cr.pid; *uid = cr.uid; } else { fprintf (stderr, "failed to getsockopt() credentials, returned len %d/%d\n", cr_len, (int) sizeof (cr)); return -1; } #elif defined(HAVE_CMSGCRED) cred = (struct cmsgcred *) CMSG_DATA (&cmsg.hdr); *pid = cred->cmcred_pid; *uid = cred->cmcred_euid; #elif defined(LOCAL_CREDS) cred = (struct sockcred *) CMSG_DATA (&cmsg.hdr); *pid = 0; *uid = cred->sc_euid; set_local_creds(sock, 0); #elif defined(HAVE_GETPEEREID) /* OpenBSD */ uid_t euid; gid_t egid; *pid = 0; if (getpeereid (sock, &euid, &egid) == 0) { *uid = euid; } else { fprintf (stderr, "getpeereid() failed: %s\n", strerror (errno)); return -1; } #elif defined(HAVE_GETPEERUCRED) ucred_t *uc = NULL; if (getpeerucred (sock, &uc) == 0) { *pid = ucred_getpid (uc); *uid = ucred_geteuid (uc); ucred_free (uc); } else { fprintf (stderr, "getpeerucred() failed: %s\n", strerror (errno)); return -1; } #else /* !SO_PEERCRED && !HAVE_CMSGCRED */ fprintf (stderr, "socket credentials not supported on this OS\n"); return -1; #endif } return 0; } int egg_unix_credentials_write (int socket) { char buf; int bytes_written; #if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__)) union { struct cmsghdr hdr; char cred[CMSG_SPACE (sizeof (struct cmsgcred))]; } cmsg; struct iovec iov; struct msghdr msg; #endif buf = 0; #if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__)) iov.iov_base = &buf; iov.iov_len = 1; memset (&msg, 0, sizeof (msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (caddr_t) &cmsg; msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred)); memset (&cmsg, 0, sizeof (cmsg)); cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred)); cmsg.hdr.cmsg_level = SOL_SOCKET; cmsg.hdr.cmsg_type = SCM_CREDS; #endif again: #if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__)) bytes_written = sendmsg (socket, &msg, 0); #else bytes_written = write (socket, &buf, 1); #endif if (bytes_written < 0 && errno == EINTR) goto again; if (bytes_written <= 0) return -1; return 0; } int egg_unix_credentials_setup (int sock) { int retval = 0; #if defined(LOCAL_CREDS) && !defined(HAVE_CMSGCRED) int val = 1; if (setsockopt (sock, 0, LOCAL_CREDS, &val, sizeof (val)) < 0) { fprintf (stderr, "unable to set LOCAL_CREDS socket option on fd %d\n", fd); retval = -1; } #endif return retval; } char* egg_unix_credentials_executable (pid_t pid) { char *result = NULL; /* Try and figure out the path from the pid */ #if defined(__linux__) || defined(__FreeBSD__) char path[1024]; char buffer[64]; int count; #if defined(__linux__) snprintf (buffer, sizeof (buffer), "/proc/%d/exe", (int)pid); #elif defined(__FreeBSD__) snprintf (buffer, sizeof (buffer), "/proc/%d/file", (int)pid); #endif count = readlink (buffer, path, sizeof (path)); if (count < 0) fprintf (stderr, "readlink failed for file: %s", buffer); else result = strndup (path, count); #endif return result; } 0707010000003D000081A400000000000000000000000167D9F0D900000832000000000000000000000000000000000000002C00000000libsecret-0.21.7/egg/egg-unix-credentials.h/* * Copyright (C) 2008 Stefan Walter * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * 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. * * The names of contributors to this software may not be * used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "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 * COPYRIGHT OWNER OR CONTRIBUTORS 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. * * Author: Stef Walter */ #ifndef EGGUNIXCREDENTIALS_H_ #define EGGUNIXCREDENTIALS_H_ #include int egg_unix_credentials_read (int sock, pid_t *pid, uid_t *uid); int egg_unix_credentials_write (int sock); int egg_unix_credentials_setup (int sock); char* egg_unix_credentials_executable (pid_t pid); #endif /*EGGUNIXCREDENTIALS_H_*/ 0707010000003E000081A400000000000000000000000167D9F0D900000532000000000000000000000000000000000000002100000000libsecret-0.21.7/egg/meson.buildlibegg_sources = [ 'egg-hex.c', 'egg-secure-memory.c', 'egg-unix-credentials.c', 'egg-buffer.c', 'egg-testing.c', ] libegg_deps = [ glib_deps, ] if with_crypto libegg_sources += [ 'egg-dh.c', ] if with_gcrypt libegg_sources += [ 'egg-dh-libgcrypt.c', 'egg-fips-libgcrypt.c', 'egg-hkdf-libgcrypt.c', 'egg-keyring1-libgcrypt.c', 'egg-libgcrypt.c', ] elif with_gnutls libegg_sources += [ 'egg-dh-gnutls.c', 'egg-fips-gnutls.c', 'egg-hkdf-gnutls.c', 'egg-keyring1-gnutls.c', ] endif libegg_deps += crypto_deps endif if get_option('tpm2') libegg_sources += [ 'egg-tpm2.c', ] libegg_deps += tss2_deps endif libegg = static_library('egg', libegg_sources, dependencies: libegg_deps, c_args: [ '-D_GNU_SOURCE', ], include_directories: [config_h_dir, build_dir], ) # Tests test_names = [ 'test-hex', 'test-secmem', ] if with_crypto test_names += [ 'test-dh', 'test-hkdf', ] endif if get_option('tpm2') test_names += [ 'test-tpm2', ] endif foreach _test : test_names test_bin = executable(_test, '@0@.c'.format(_test), dependencies: libegg_deps, link_with: libegg, include_directories: config_h_dir, ) test(_test, test_bin, suite: 'libegg', ) endforeach 0707010000003F000081A400000000000000000000000167D9F0D9000011A7000000000000000000000000000000000000001F00000000libsecret-0.21.7/egg/test-dh.c/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* test-dh.c: Test egg-dh.c Copyright (C) 2009 Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, see . Author: Stef Walter */ #include "config.h" #undef G_DISABLE_ASSERT #include "egg/egg-dh.h" #include "egg/egg-secure-memory.h" #include "egg/egg-testing.h" #include #include #include #include EGG_SECURE_DEFINE_GLIB_GLOBALS (); static void test_perform (void) { egg_dh_params *params; egg_dh_pubkey *y1; egg_dh_privkey *x1; egg_dh_pubkey *y2; egg_dh_privkey *x2; GBytes *k1, *k2; gboolean ret; /* Load up the parameters */ params = egg_dh_default_params ("ietf-ike-grp-modp-768"); if (!params) g_assert_not_reached (); /* Generate secrets */ ret = egg_dh_gen_pair (params, 0, &y1, &x1); g_assert_true (ret); ret = egg_dh_gen_pair (params, 0, &y2, &x2); g_assert_true (ret); /* Calculate keys */ k1 = egg_dh_gen_secret (y1, x2, params); g_assert_nonnull (k1); k2 = egg_dh_gen_secret (y2, x1, params); g_assert_nonnull (k2); /* Keys must be the same */ g_assert_cmpmem (g_bytes_get_data (k1, NULL), g_bytes_get_size (k1), g_bytes_get_data (k2, NULL), g_bytes_get_size (k2)); egg_dh_params_free (params); egg_dh_pubkey_free (y1); egg_dh_privkey_free (x1); egg_secure_free (k1); egg_dh_pubkey_free (y2); egg_dh_privkey_free (x2); egg_secure_free (k2); } static void test_short_pair (void) { egg_dh_params *params; egg_dh_pubkey *y1; egg_dh_privkey *x1; GBytes *bytes; gboolean ret; /* Load up the parameters */ params = egg_dh_default_params ("ietf-ike-grp-modp-1024"); g_assert_nonnull (params); /* Generate secrets */ ret = egg_dh_gen_pair (params, 512, &y1, &x1); g_assert_true (ret); bytes = egg_dh_pubkey_export (y1); g_assert_cmpuint (g_bytes_get_size (bytes), <=, 512); g_bytes_unref (bytes); egg_dh_params_free (params); egg_dh_pubkey_free (y1); egg_dh_privkey_free (x1); } static void check_dh_default (const gchar *name, guint bits) { gboolean ret; gconstpointer prime, base; gsize n_prime, n_base; ret = egg_dh_default_params_raw (name, &prime, &n_prime, &base, &n_base); g_assert_true (ret); g_assert_nonnull (prime); egg_assert_cmpsize (n_prime, >, 0); g_assert_nonnull (base); egg_assert_cmpsize (n_base, >, 0); } static void test_default_768 (void) { check_dh_default ("ietf-ike-grp-modp-768", 768); } static void test_default_1024 (void) { check_dh_default ("ietf-ike-grp-modp-1024", 1024); } static void test_default_1536 (void) { check_dh_default ("ietf-ike-grp-modp-1536", 1536); } static void test_default_2048 (void) { check_dh_default ("ietf-ike-grp-modp-2048", 2048); } static void test_default_3072 (void) { check_dh_default ("ietf-ike-grp-modp-3072", 3072); } static void test_default_4096 (void) { check_dh_default ("ietf-ike-grp-modp-4096", 4096); } static void test_default_8192 (void) { check_dh_default ("ietf-ike-grp-modp-8192", 8192); } static void test_default_bad (void) { egg_dh_params *params; params = egg_dh_default_params ("bad-name"); g_assert_null (params); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); if (!g_test_quick ()) { g_test_add_func ("/dh/perform", test_perform); g_test_add_func ("/dh/short_pair", test_short_pair); } g_test_add_func ("/dh/default_768", test_default_768); g_test_add_func ("/dh/default_1024", test_default_1024); g_test_add_func ("/dh/default_1536", test_default_1536); g_test_add_func ("/dh/default_2048", test_default_2048); g_test_add_func ("/dh/default_3072", test_default_3072); g_test_add_func ("/dh/default_4096", test_default_4096); g_test_add_func ("/dh/default_8192", test_default_8192); g_test_add_func ("/dh/default_bad", test_default_bad); return g_test_run (); } 07070100000040000081A400000000000000000000000167D9F0D900000C95000000000000000000000000000000000000002000000000libsecret-0.21.7/egg/test-hex.c/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* unit-test-util.c: Test gck-util.c Copyright (C) 2007 Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, see . Author: Stef Walter */ #include "config.h" #undef G_DISABLE_ASSERT #include "egg/egg-hex.h" #include #include #include static const guchar TEST_DATA[] = { 0x05, 0xD6, 0x95, 0x96, 0x10, 0x12, 0xAE, 0x35 }; static const gchar *TEST_HEX = "05D695961012AE35"; static const gchar *TEST_HEX_DELIM = "05 D6 95 96 10 12 AE 35"; static void test_encode (void) { gchar *hex; hex = egg_hex_encode (TEST_DATA, sizeof (TEST_DATA)); g_assert_nonnull (hex); g_assert_cmpstr (hex, ==, TEST_HEX); g_free (hex); } static void test_encode_spaces (void) { gchar *hex; /* Encode without spaces */ hex = egg_hex_encode_full (TEST_DATA, sizeof (TEST_DATA), TRUE, 0, 0); g_assert_nonnull (hex); g_assert_cmpstr (hex, ==, TEST_HEX); g_free (hex); /* Encode with spaces */ hex = egg_hex_encode_full (TEST_DATA, sizeof (TEST_DATA), TRUE, " ", 1); g_assert_nonnull (hex); g_assert_cmpstr (hex, ==, TEST_HEX_DELIM); g_free (hex); } static void test_decode (void) { guchar *data; gsize n_data; data = egg_hex_decode (TEST_HEX, -1, &n_data); g_assert_nonnull (data); g_assert_cmpuint (n_data, ==, sizeof (TEST_DATA)); g_assert_true (memcmp (data, TEST_DATA, n_data) == 0); g_free (data); /* Nothing in, empty out */ data = egg_hex_decode ("AB", 0, &n_data); g_assert_nonnull (data); g_assert_cmpuint (n_data, ==, 0); g_free (data); /* Delimited*/ data = egg_hex_decode_full (TEST_HEX_DELIM, -1, " ", 1, &n_data); g_assert_nonnull (data); g_assert_cmpuint (n_data, ==, sizeof (TEST_DATA)); g_assert_true (memcmp (data, TEST_DATA, n_data) == 0); g_free (data); } static void test_decode_fail (void) { guchar *data; gsize n_data; /* Invalid input, null out */ data = egg_hex_decode ("AB", 1, &n_data); g_assert_null (data); /* Bad characters, null out */ data = egg_hex_decode ("ABXX", -1, &n_data); g_assert_null (data); /* Not Delimited, null out*/ data = egg_hex_decode_full ("ABABAB", -1, ":", 1, &n_data); g_assert_null (data); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/hex/encode", test_encode); g_test_add_func ("/hex/encode_spaces", test_encode_spaces); g_test_add_func ("/hex/decode", test_decode); g_test_add_func ("/hex/decode_fail", test_decode_fail); return g_test_run (); } 07070100000041000081A400000000000000000000000167D9F0D900003D65000000000000000000000000000000000000002100000000libsecret-0.21.7/egg/test-hkdf.c/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* test-hkdf.c: Test egg-hkdf.c Copyright (C) 2011 Collabora Ltd. The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, see . Author: Stef Walter */ #include "config.h" #undef G_DISABLE_ASSERT #include #include #include #include "egg/egg-hkdf.h" #include "egg/egg-secure-memory.h" #include "egg/egg-testing.h" #undef G_DISABLE_ASSERT EGG_SECURE_DEFINE_GLIB_GLOBALS (); static void test_hkdf_test_case_1 (void) { /* RFC 5869: A.1 Test Case 1 */ const guchar ikm[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; const guchar salt[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; const guchar info[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; const guchar okm[] = { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65 }; guchar buffer[sizeof (okm)]; gboolean ret; egg_assert_cmpsize (sizeof (ikm), ==, 22); egg_assert_cmpsize (sizeof (salt), ==, 13); egg_assert_cmpsize (sizeof (info), ==, 10); egg_assert_cmpsize (sizeof (okm), ==, 42); memset (buffer, 0, sizeof (buffer)); ret = egg_hkdf_perform ("sha256", ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), buffer, sizeof (buffer)); g_assert_true (ret); egg_assert_cmpmem (buffer, sizeof (buffer), ==, okm, sizeof (okm)); } static void test_hkdf_test_case_2 (void) { /* RFC 5869: A.2 Test Case 2 */ const guchar ikm[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; const guchar salt[] = { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf }; const guchar info[] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; const guchar okm[] = { 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87 }; guchar buffer[sizeof (okm)]; gboolean ret; egg_assert_cmpsize (sizeof (ikm), ==, 80); egg_assert_cmpsize (sizeof (salt), ==, 80); egg_assert_cmpsize (sizeof (info), ==, 80); egg_assert_cmpsize (sizeof (okm), ==, 82); memset (buffer, 0, sizeof (buffer)); ret = egg_hkdf_perform ("sha256", ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), buffer, sizeof (buffer)); g_assert_true (ret); egg_assert_cmpmem (buffer, sizeof (buffer), ==, okm, sizeof (okm)); } static void test_hkdf_test_case_3 (void) { /* RFC 5869: A.3 Test Case 3 */ const guchar ikm[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,}; const guchar salt[] = { }; const guchar info[] = { }; const guchar okm[] = { 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8 }; guchar buffer[sizeof (okm)]; gboolean ret; egg_assert_cmpsize (sizeof (ikm), ==, 22); egg_assert_cmpsize (sizeof (salt), ==, 0); egg_assert_cmpsize (sizeof (info), ==, 0); egg_assert_cmpsize (sizeof (okm), ==, 42); memset (buffer, 0, sizeof (buffer)); ret = egg_hkdf_perform ("sha256", ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), buffer, sizeof (buffer)); g_assert_true (ret); egg_assert_cmpmem (buffer, sizeof (buffer), ==, okm, sizeof (okm)); } static void test_hkdf_test_case_4 (void) { /* RFC 5869: A.4 Test Case 4 */ const guchar ikm[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; const guchar salt[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; const guchar info[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; const guchar okm[] = { 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15, 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, 0xf8, 0x96 }; guchar buffer[sizeof (okm)]; gboolean ret; egg_assert_cmpsize (sizeof (ikm), ==, 11); egg_assert_cmpsize (sizeof (salt), ==, 13); egg_assert_cmpsize (sizeof (info), ==, 10); egg_assert_cmpsize (sizeof (okm), ==, 42); memset (buffer, 0, sizeof (buffer)); ret = egg_hkdf_perform ("sha1", ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), buffer, sizeof (buffer)); g_assert_true (ret); egg_assert_cmpmem (buffer, sizeof (buffer), ==, okm, sizeof (okm)); } static void test_hkdf_test_case_5 (void) { /* RFC 5869: A.5 Test Case 5 */ const guchar ikm[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; const guchar salt[] = { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf }; const guchar info[] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; const guchar okm[] = { 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 }; guchar buffer[sizeof (okm)]; gboolean ret; egg_assert_cmpsize (sizeof (ikm), ==, 80); egg_assert_cmpsize (sizeof (salt), ==, 80); egg_assert_cmpsize (sizeof (info), ==, 80); egg_assert_cmpsize (sizeof (okm), ==, 82); memset (buffer, 0, sizeof (buffer)); ret = egg_hkdf_perform ("sha1", ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), buffer, sizeof (buffer)); g_assert_true (ret); egg_assert_cmpmem (buffer, sizeof (buffer), ==, okm, sizeof (okm)); } static void test_hkdf_test_case_6 (void) { /* RFC 5869: A.6 Test Case 6 */ const guchar ikm[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; const guchar salt[] = { }; const guchar info[] = { }; const guchar okm[] = { 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, 0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06, 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06, 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0, 0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, 0x49, 0x18 }; guchar buffer[sizeof (okm)]; gboolean ret; egg_assert_cmpsize (sizeof (ikm), ==, 22); egg_assert_cmpsize (sizeof (salt), ==, 0); egg_assert_cmpsize (sizeof (info), ==, 0); egg_assert_cmpsize (sizeof (okm), ==, 42); memset (buffer, 0, sizeof (buffer)); ret = egg_hkdf_perform ("sha1", ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), buffer, sizeof (buffer)); g_assert_true (ret); egg_assert_cmpmem (buffer, sizeof (buffer), ==, okm, sizeof (okm)); } static void test_hkdf_test_case_7 (void) { /* RFC 5869: A.7 Test Case 7 */ const guchar ikm[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }; const guchar *salt = NULL; const guchar info[] = { }; const guchar okm[] = { 0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a, 0xb3, 0xba, 0xe5, 0x48, 0xaa, 0x53, 0xd4, 0x23, 0xb0, 0xd1, 0xf2, 0x7e, 0xbb, 0xa6, 0xf5, 0xe5, 0x67, 0x3a, 0x08, 0x1d, 0x70, 0xcc, 0xe7, 0xac, 0xfc, 0x48 }; guchar buffer[sizeof (okm)]; gboolean ret; egg_assert_cmpsize (sizeof (ikm), ==, 22); egg_assert_cmpsize (sizeof (info), ==, 0); egg_assert_cmpsize (sizeof (okm), ==, 42); memset (buffer, 0, sizeof (buffer)); ret = egg_hkdf_perform ("sha1", ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), buffer, sizeof (buffer)); g_assert_true (ret); egg_assert_cmpmem (buffer, sizeof (buffer), ==, okm, sizeof (okm)); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/hkdf/test-case-1", test_hkdf_test_case_1); g_test_add_func ("/hkdf/test-case-2", test_hkdf_test_case_2); g_test_add_func ("/hkdf/test-case-3", test_hkdf_test_case_3); g_test_add_func ("/hkdf/test-case-4", test_hkdf_test_case_4); g_test_add_func ("/hkdf/test-case-5", test_hkdf_test_case_5); g_test_add_func ("/hkdf/test-case-6", test_hkdf_test_case_6); g_test_add_func ("/hkdf/test-case-7", test_hkdf_test_case_7); return g_test_run (); } 07070100000042000081A400000000000000000000000167D9F0D9000018CA000000000000000000000000000000000000002300000000libsecret-0.21.7/egg/test-secmem.c/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* unit-test-secmem.c: Test low level secure memory allocation functionality Copyright (C) 2007 Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, see . Author: Stef Walter */ #include "config.h" #undef G_DISABLE_ASSERT #include "egg/egg-secure-memory.h" #include #include #include #include EGG_SECURE_DEFINE_GLIB_GLOBALS (); /* Declared in egg-secure-memory.c */ extern int egg_secure_warnings; EGG_SECURE_DECLARE (tests); /* * Each test looks like (on one line): * void unit_test_xxxxx (CuTest* cu) * * Each setup looks like (on one line): * void unit_setup_xxxxx (void); * * Each teardown looks like (on one line): * void unit_teardown_xxxxx (void); * * Tests be run in the order specified here. */ static gsize find_non_zero (gpointer mem, gsize len) { guchar *b, *e; gsize sz = 0; for (b = (guchar*)mem, e = ((guchar*)mem) + len; b != e; ++b, ++sz) { if (*b != 0x00) return sz; } return G_MAXSIZE; } static void test_alloc_free (void) { gpointer p; gboolean ret; p = egg_secure_alloc_full ("tests", 512, 0); g_assert_nonnull (p); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p, 512)); memset (p, 0x67, 512); ret = egg_secure_check (p); g_assert_true (ret); egg_secure_free_full (p, 0); } static void test_realloc_across (void) { gpointer p, p2; /* Tiny allocation */ p = egg_secure_realloc_full ("tests", NULL, 1088, 0); g_assert_nonnull (p); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p, 1088)); /* Reallocate to a large one, will have to have changed blocks */ p2 = egg_secure_realloc_full ("tests", p, 16200, 0); g_assert_nonnull (p2); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p2, 16200)); egg_secure_free (p2); } static void test_alloc_two (void) { gpointer p, p2; gboolean ret; p2 = egg_secure_alloc_full ("tests", 4, 0); g_assert_nonnull (p2); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p2, 4)); memset (p2, 0x67, 4); p = egg_secure_alloc_full ("tests", 16200, 0); g_assert_nonnull (p); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p, 16200)); memset (p, 0x67, 16200); ret = egg_secure_check (p); g_assert_true (ret); egg_secure_free_full (p2, 0); egg_secure_free_full (p, 0); } static void test_realloc (void) { gchar *str = "a test string to see if realloc works properly"; gpointer p, p2; gsize len; len = strlen (str) + 1; p = egg_secure_realloc_full ("tests", NULL, len, 0); g_assert_nonnull (p); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p, len)); strcpy ((gchar*)p, str); p2 = egg_secure_realloc_full ("tests", p, 512, 0); g_assert_nonnull (p2); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (((gchar*)p2) + len, 512 - len)); g_assert_cmpstr (p2, ==, str); p = egg_secure_realloc_full ("tests", p2, 0, 0); g_assert_null (p); } static void test_multialloc (void) { GPtrArray *memory; gpointer data; gsize size; int i, action, index; /* A predetermined seed to get a predetermined pattern */ g_random_set_seed (15); memory = g_ptr_array_new (); /* Don't print "can't allocate" warnings */ egg_secure_warnings = 0; for (i = 0; TRUE; ++i) { /* Determine what we want to do */ if (memory->len > 0) { if (i > 100000) /* Once we've done 100000 alocations start freeing */ action = 2; else action = g_random_int_range (0, 3); } else { action = 0; /* No allocations, so allocate */ } switch (action) { case 0: /* Allocate some memory */ size = g_random_int_range (1, 16384); data = egg_secure_alloc (size); g_assert_nonnull (data); memset (data, 0xCAFEBABE, size); g_ptr_array_add (memory, data); break; case 1: /* Reallocate some memory */ index = g_random_int_range (0, memory->len); data = g_ptr_array_index (memory, index); g_assert_nonnull (data); size = g_random_int_range (1, 16384); data = egg_secure_realloc (data, size); g_assert_nonnull (data); memset (data, 0xCAFEBABE, size); g_ptr_array_index (memory, index) = data; break; case 2: /* Free some memory */ index = g_random_int_range (0, memory->len); data = g_ptr_array_remove_index_fast (memory, index); g_assert_nonnull (data); egg_secure_free (data); break; default: g_assert_not_reached (); } egg_secure_validate (); if (i > 100000 && !memory->len) break; } g_assert_true (memory->len == 0); g_ptr_array_free (memory, TRUE); egg_secure_warnings = 1; } static void test_clear (void) { gpointer p; p = egg_secure_alloc_full ("tests", 188, 0); g_assert_nonnull (p); memset (p, 0x89, 188); g_assert_true (memchr (p, 0x89, 188) == p); egg_secure_clear (p, 188); g_assert_null (memchr (p, 0x89, 188)); egg_secure_free_full (p, 0); } static void test_strclear (void) { gchar *str; str = egg_secure_strdup ("secret"); g_assert_nonnull (str); g_assert_cmpuint (strlen (str), ==, 6); g_assert_true (strchr (str, 't') == str + 5); egg_secure_strclear (str); g_assert_cmpuint (strlen (str), ==, 6); g_assert_null (strchr (str, 't')); egg_secure_free_full (str, 0); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/secmem/alloc_free", test_alloc_free); g_test_add_func ("/secmem/realloc_across", test_realloc_across); g_test_add_func ("/secmem/alloc_two", test_alloc_two); g_test_add_func ("/secmem/realloc", test_realloc); g_test_add_func ("/secmem/multialloc", test_multialloc); g_test_add_func ("/secmem/clear", test_clear); g_test_add_func ("/secmem/strclear", test_strclear); return g_test_run (); } 07070100000043000081A400000000000000000000000167D9F0D90000093E000000000000000000000000000000000000002100000000libsecret-0.21.7/egg/test-tpm2.c/* libsecret - Test TSS interface for libsecret * * Copyright (C) 2021 Dhanuka Warusadura * * 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 * * Author: Dhanuka Warusadura */ #include "egg-tpm2.h" void test_egg_tpm2_generate_master_password(void) { EggTpm2Context *context; GBytes *result; GError *error = NULL; g_assert_no_error(error); context = egg_tpm2_initialize(&error); g_assert_nonnull(context); result = egg_tpm2_generate_master_password(context, &error); g_assert_nonnull(result); egg_tpm2_finalize(context); g_bytes_unref(result); } void test_egg_tpm2_decrypt_master_password(void) { EggTpm2Context *context; GBytes *result, *decrypted1, *decrypted2; GError *error = NULL; g_assert_no_error(error); context = egg_tpm2_initialize(&error); g_assert_nonnull(context); result = egg_tpm2_generate_master_password(context, &error); g_assert_nonnull(result); egg_tpm2_finalize(context); context = egg_tpm2_initialize(&error); decrypted1 = egg_tpm2_decrypt_master_password(context, result, &error); g_assert_nonnull(decrypted1); decrypted2 = egg_tpm2_decrypt_master_password(context, result, &error); g_assert_nonnull(decrypted2); g_assert(g_bytes_equal(decrypted1, decrypted2)); egg_tpm2_finalize(context); g_bytes_unref(result); g_bytes_unref(decrypted1); g_bytes_unref(decrypted2); } int main (int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); g_test_add_func( "/tpm/test_egg_tpm2_generate_master_password", test_egg_tpm2_generate_master_password); g_test_add_func( "/tpm/test_egg_tpm2_decrypt_master_password", test_egg_tpm2_decrypt_master_password); return g_test_run(); } 07070100000044000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000001B00000000libsecret-0.21.7/libsecret07070100000045000081A400000000000000000000000167D9F0D9000006F6000000000000000000000000000000000000002000000000libsecret-0.21.7/libsecret.doap libsecret Secret Service D-Bus client library libsecret is a client for the Secret Service D-Bus API. The Secret Service allows storage of passwords in a common way on the desktop. Supported by gnome-keyring and ksecretservice. C Daiki Ueno dueno Niels De Graef nielsdg Dhanuka Warusadura dhanuka 07070100000046000081A400000000000000000000000167D9F0D900000A6B000000000000000000000000000000000000002D00000000libsecret-0.21.7/libsecret/Secret-1.metadata// Metadata file for Vala API generation. // See https://live.gnome.org/Vala/UpstreamGuide for more information attributes_build skip=false attributes_buildv skip=false password_lookup skip=false password_lookup_sync skip=false throws="GLib.Error" .error skip password_lookupv finish_name="secret_password_lookup_finish" password_clear skip=false password_clear_sync skip=false throws="GLib.Error" .error skip password_clearv finish_name="secret_password_clear_finish" password_store skip=false password_store_sync skip=false throws="GLib.Error" .error skip password_storev finish_name="secret_password_store_finish" password_searchv finish_name="secret_password_search_finish" Schema .new skip=false Collection .new_for_dbus_path skip=false .new_for_dbus_path_finish skip=false .new_for_dbus_path_sync skip=false .search_for_dbus_paths skip=false .search_for_dbus_paths_finish skip=false .search_for_dbus_paths_sync skip=false Item .new_for_dbus_path skip=false .new_for_dbus_path_finish skip=false .new_for_dbus_path_sync skip=false Service .search_for_dbus_paths skip=false .search_for_dbus_paths_finish skip=false .search_for_dbus_paths_sync skip=false .get_secret_for_dbus_path skip=false .get_secret_for_dbus_path_finish skip=false .get_secret_for_dbus_path_sync skip=false .get_secrets_for_dbus_paths skip=false .get_secrets_for_dbus_paths_finish skip=false .get_secrets_for_dbus_paths_sync skip=false .lock_dbus_paths_sync skip=false .lock_dbus_paths skip=false .lock_dbus_paths_finish skip=false .unlock_dbus_paths_sync skip=false .unlock_dbus_paths skip=false .unlock_dbus_paths_finish skip=false .delete_item_dbus_path skip=false .delete_item_dbus_path_finish skip=false .delete_item_dbus_path_sync skip=false .create_collection_dbus_path skip=false .create_collection_dbus_path_finish skip=false .create_collection_dbus_path_sync skip=false .create_item_dbus_path skip=false .create_item_dbus_path_finish skip=false .create_item_dbus_path_sync skip=false .read_alias_dbus_path skip=false .read_alias_dbus_path_finish skip=false nullable=true .read_alias_dbus_path_sync skip=false nullable=true .set_alias_to_dbus_path skip=false .set_alias_to_dbus_path_finish skip=false .set_alias_to_dbus_path_sync skip=false .prompt_at_dbus_path_sync skip=false nullable=true .prompt_at_dbus_path skip=false .prompt_at_dbus_path_finish skip=false nullable=true Backend .search_finish skip=false type="GLib.List" .*#virtual_method.schema nullable .*#virtual_method.attributes type="GLib.HashTable" .*#virtual_method.collection nullable 07070100000047000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000002400000000libsecret-0.21.7/libsecret/fixtures07070100000048000081A400000000000000000000000167D9F0D90000021A000000000000000000000000000000000000003400000000libsecret-0.21.7/libsecret/fixtures/default.keyringGnomeKeyring  :p.Z|^AL@KWhsg]barZ9=ǭ ա?Q XbazLhiQ>^w؇Cpٕ#{븶foovk.ȟ£bBV1a%JoLڗi&rYX%!?w<Nȼ 7͔Y@^C_b9t>[gC!8@ `GkI၄副oܹ|5GCrapplevk.ȟ£bBV1abananaLhiQ>^w؇Cpٕ#{븶orangeZ9=ǭ ա?Q X'OwW>:e h!o)U~P}\q59BUW_A=N}t,>ImsaTc;!p60 ɥD1L&^["z$07070100000049000081A400000000000000000000000167D9F0D900002185000000000000000000000000000000000000002700000000libsecret-0.21.7/libsecret/meson.buildinstalled_headers_subdir_base = 'libsecret-@0@'.format(api_version_major) installed_headers_subdir = installed_headers_subdir_base / 'libsecret' libsecret_sources = [ 'secret-attributes.c', 'secret-backend.c', 'secret-collection.c', 'secret-item.c', 'secret-methods.c', 'secret-password.c', 'secret-prompt.c', 'secret-retrievable.c', 'secret-schema.c', 'secret-schemas.c', 'secret-service.c', 'secret-value.c', 'secret-paths.c', 'secret-session.c', 'secret-util.c', ] libsecret_headers = [ 'secret.h', 'secret-attributes.h', 'secret-backend.h', 'secret-collection.h', 'secret-item.h', 'secret-password.h', 'secret-paths.h', 'secret-prompt.h', 'secret-retrievable.h', 'secret-schema.h', 'secret-schemas.h', 'secret-service.h', 'secret-types.h', 'secret-value.h', ] if with_crypto libsecret_sources += [ 'secret-file-backend.c', 'secret-file-collection.c', 'secret-file-item.c', ] endif version_numbers = meson.project_version().split('.') version_major = version_numbers[0].to_int() version_minor = version_numbers[1].to_int() version_micro = version_numbers[2].to_int() version_h_conf = configuration_data({ 'SECRET_MAJOR_VERSION': version_major, 'SECRET_MINOR_VERSION': version_minor, 'SECRET_MICRO_VERSION': version_micro, }) version_h = configure_file(input: 'secret-version.h.in', output: '@BASENAME@', configuration: version_h_conf) libsecret_headers += version_h _dbus_generated = gnome.gdbus_codegen('secret-dbus-generated', sources: 'org.freedesktop.Secrets.xml', interface_prefix: 'org.freedesktop.Secret.', namespace: '_SecretGen', ) _enums_generated = gnome.mkenums('secret-enum-types', sources: libsecret_headers, c_template: 'secret-enum-types.c.template', h_template: 'secret-enum-types.h.template', install_header: true, install_dir: get_option('includedir') / installed_headers_subdir, ) libsecret_dependencies = [ glib_deps, ] if with_crypto libsecret_dependencies += crypto_deps endif libsecret_cflags = [ '-DSECRET_COMPILATION', ] libsecret = library('secret-@0@'.format(api_version_major), [ libsecret_sources, _dbus_generated, _enums_generated ], version: libtool_version, dependencies: libsecret_dependencies, link_with: libegg, c_args: libsecret_cflags, include_directories: config_h_dir, install: true, ) install_headers(libsecret_headers, subdir: installed_headers_subdir, ) libsecret_dep = declare_dependency( link_with: [ libsecret, libegg ], dependencies: libsecret_dependencies, ) # GObject Introspection if get_option('introspection') libsecret_gir_sources = [ 'secret-attributes.c', 'secret-attributes.h', 'secret-backend.c', 'secret-backend.h', 'secret-collection.c', 'secret-collection.h', 'secret-item.c', 'secret-item.h', 'secret-methods.c', 'secret-password.c', 'secret-password.h', 'secret-paths.c', 'secret-paths.h', 'secret-prompt.c', 'secret-prompt.h', 'secret-retrievable.c', 'secret-retrievable.h', 'secret-schema.c', 'secret-schema.h', 'secret-schemas.c', 'secret-schemas.h', 'secret-service.c', 'secret-service.h', 'secret-types.h', 'secret-value.c', 'secret-value.h', 'secret-util.c', ] libsecret_gir_sources += version_h libsecret_gir_sources += _enums_generated libsecret_gir = gnome.generate_gir(libsecret, sources: libsecret_gir_sources, namespace: 'Secret', nsversion: api_version_major, export_packages: 'libsecret-@0@'.format(api_version_major), includes: [ 'GObject-2.0', 'Gio-2.0' ], header: 'libsecret/secret.h', extra_args: [ '-D SECRET_COMPILATION'], install: true, ) # Vapi if get_option('vapi') libsecret_vapi = gnome.generate_vapi('libsecret-@0@'.format(api_version_major), sources: libsecret_gir[0], metadata_dirs: meson.source_root() / 'libsecret', packages: [ 'gobject-2.0', 'gio-2.0' ], install: true, ) endif endif # pkg-config libsecret_pc_variables = [ 'exec_prefix=${prefix}', 'datarootdir=@0@'.format('${prefix}' / get_option('datadir')), 'datadir=${datarootdir}', 'sysconfdir=@0@'.format('${prefix}' / get_option('sysconfdir')) ] pkg.generate(libsecret, description: 'GObject bindings for Secret Service API', name: 'libsecret-@0@'.format(api_version_major), subdirs: installed_headers_subdir_base, variables: libsecret_pc_variables, requires: glib_deps, ) pkg.generate(description: 'GObject bindings for Secret Service API (Unstable)', name: 'libsecret-unstable', variables: libsecret_pc_variables, extra_cflags: '-DSECRET_WITH_UNSTABLE', requires: libsecret, ) # Tests test_cflags = [ libsecret_cflags, '-DSRCDIR="@0@"'.format(meson.source_root()), ] mock_service_lib = library('mock-service', 'mock-service.c', dependencies: glib_deps, c_args: test_cflags, include_directories: config_h_dir, ) if get_option('introspection') mock_service_gir = gnome.generate_gir(mock_service_lib, sources: files('mock-service.c', 'mock-service.h'), namespace: 'MockService', nsversion: '0', export_packages: 'mock-service-0', includes: [ 'GObject-2.0', 'Gio-2.0' ], header: 'libsecret/mock-service.h', ) if get_option('vapi') mock_service_vapi = gnome.generate_vapi('mock-service-0', sources: mock_service_gir[0], packages: [ 'gobject-2.0', 'gio-2.0', libsecret_vapi, ], ) endif endif # C tests test_names = [ 'test-attributes', 'test-value', 'test-prompt', 'test-service', 'test-session', 'test-paths', 'test-methods', 'test-password', 'test-item', 'test-collection', ] if with_crypto test_names += [ 'test-file-collection', ] endif foreach _test : test_names test_bin = executable(_test, '@0@.c'.format(_test), dependencies: libsecret_dep, link_with: mock_service_lib, include_directories: config_h_dir, c_args: test_cflags, ) test(_test, test_bin, suite: 'libsecret', ) endforeach # Tests with introspection if get_option('introspection') # env to be used in tests that use the typelib, # to make sure they find the one for MockService test_typelib_env = environment() test_typelib_env.prepend('GI_TYPELIB_PATH', meson.current_build_dir()) test_typelib_env.prepend('LD_LIBRARY_PATH', meson.current_build_dir()) # Python Tests pytest_names = [ 'test-py-lookup', 'test-py-clear', 'test-py-store', ] pymod = import('python') python3 = pymod.find_installation() foreach _pytest : pytest_names py_test = meson.current_source_dir() / _pytest + '.py' test(_pytest, python3, args: py_test, depends: mock_service_gir[1], env: test_typelib_env, suite: 'python', ) endforeach # JS Tests jstest_names = [ 'test-js-lookup', 'test-js-clear', 'test-js-store', ] gjs = find_program('gjs', required: false) if gjs.found() foreach _jstest : jstest_names js_test = meson.current_source_dir() / _jstest + '.js' test(_jstest, gjs, args: js_test, depends: mock_service_gir[1], env: test_typelib_env, suite: 'javascript', ) endforeach else message('GJS not found. Not running Javascript tests') endif # Vala tests # FIXME: Don't add Vala tests when generating a coverage build, as this # will fail due to https://github.com/mesonbuild/meson/issues/7426 if get_option('vapi') and not get_option('b_coverage') # FIXME: the "native" kwarg should be added once we can require meson ≥0.54 add_languages('vala') valac = meson.get_compiler('vala') valatests = [ { 'name': 'test-vala-lang', 'cflags': [ '-Wno-unused-but-set-variable' ], }, { 'name': 'test-vala-unstable', 'cflags': [ '-DSECRET_WITH_UNSTABLE', '-DSECRET_API_SUBJECT_TO_CHANGE' ], }, ] foreach _valatest: valatests name = _valatest['name'] extra_cflags = _valatest['cflags'] test_bin = executable(name, '@0@.vala'.format(name), dependencies: [ glib_deps, valac.find_library('glib-2.0'), valac.find_library('gio-2.0'), libsecret_vapi, mock_service_vapi, ], link_with: mock_service_lib, include_directories: config_h_dir, c_args: test_cflags + extra_cflags, ) test(name, test_bin, suite: 'vala', ) endforeach endif endif 0707010000004A000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000002000000000libsecret-0.21.7/libsecret/mock0707010000004B000081A400000000000000000000000167D9F0D9000003E1000000000000000000000000000000000000003200000000libsecret-0.21.7/libsecret/mock-service-delete.py#!/usr/bin/env python # # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # import dbus import mock import sys service = mock.SecretService() service.add_standard_objects() collection = mock.SecretCollection(service, "todelete", locked=False) mock.SecretItem(collection, "item", attributes={ "number": "1", "string": "one", "even": "false" }, secret="uno") mock.SecretItem(collection, "confirm", attributes={ "number": "2", "string": "two", "even": "true" }, secret="dos", confirm=True) collection = mock.SecretCollection(service, "twodelete", locked=True) mock.SecretItem(collection, "locked", attributes={ "number": "3", "string": "three", "even": "false" }, secret="tres") service.listen() 0707010000004C000081A400000000000000000000000167D9F0D9000001B1000000000000000000000000000000000000003100000000libsecret-0.21.7/libsecret/mock-service-empty.py#!/usr/bin/env python # # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # import mock service = mock.SecretService() service.listen() 0707010000004D000081A400000000000000000000000167D9F0D9000003FE000000000000000000000000000000000000003000000000libsecret-0.21.7/libsecret/mock-service-lock.py#!/usr/bin/env python # # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # import dbus import mock import sys service = mock.SecretService() service.add_standard_objects() collection = mock.SecretCollection(service, "lockone", locked=False, confirm=False) mock.SecretItem(collection, "item", attributes={ "number": "1", "string": "one", "even": "false" }, secret="uno") mock.SecretItem(collection, "confirm", attributes={ "number": "2", "string": "two", "even": "true" }, secret="dos", confirm=True) collection = mock.SecretCollection(service, "lockprompt", locked=True, confirm=True) mock.SecretItem(collection, "locked", attributes={ "number": "3", "string": "three", "even": "false" }, secret="tres") service.listen() 0707010000004E000081A400000000000000000000000167D9F0D9000001D0000000000000000000000000000000000000003200000000libsecret-0.21.7/libsecret/mock-service-normal.py#!/usr/bin/env python # # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # import mock service = mock.SecretService() service.add_standard_objects() service.listen() 0707010000004F000081A400000000000000000000000167D9F0D900000208000000000000000000000000000000000000003600000000libsecret-0.21.7/libsecret/mock-service-only-plain.py#!/usr/bin/env python # # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # import mock service = mock.SecretService() service.add_standard_objects() service.algorithms = { "plain": mock.PlainAlgorithm() } service.listen() 07070100000050000081A400000000000000000000000167D9F0D9000006D2000000000000000000000000000000000000003200000000libsecret-0.21.7/libsecret/mock-service-prompt.py#!/usr/bin/env python # # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # import dbus import mock import sys class ErrorPrompt(mock.SecretPrompt): def __init__(self, service, sender, prompt_name): mock.SecretPrompt.__init__(self, service, sender, prompt_name) @dbus.service.method('org.freedesktop.Secret.Prompt') def Prompt(self, window_id): raise mock.NotSupported("This should cause prompting to fail") class VanishPrompt(mock.SecretPrompt): def __init__(self, service, sender, prompt_name): mock.SecretPrompt.__init__(self, service, sender, prompt_name) @dbus.service.method('org.freedesktop.Secret.Prompt') def Prompt(self, window_id): sys.exit(0) class WindowPrompt(mock.SecretPrompt): def __init__(self, service, sender, prompt_name): mock.SecretPrompt.__init__(self, service, sender, prompt_name) @dbus.service.method('org.freedesktop.Secret.Prompt') def Prompt(self, window_id): self.result = dbus.String(window_id, variant_level=1) mock.SecretPrompt.Prompt(self, window_id) service = mock.SecretService() service.add_standard_objects() mock.SecretPrompt(service, None, "simple") mock.SecretPrompt(service, None, "delay", delay=0.1) def prompt_callback(): return dbus.String("Special Result", variant_level=1) mock.SecretPrompt(service, None, "result", action=prompt_callback) ErrorPrompt(service, None, "error") VanishPrompt(service, None, "vanish") WindowPrompt(service, None, "window") service.listen() 07070100000051000081A400000000000000000000000167D9F0D900000C5F000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/mock-service.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Red Hat Inc. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "mock-service.h" #include "secret-private.h" #include #include #include #ifdef __linux #include #endif static gchar *service_name = NULL; static GPid pid = 0; static void on_python_child_setup (gpointer user_data) { #ifdef __linux prctl (PR_SET_PDEATHSIG, 15); #endif } static gchar * read_until_end (int fd, GError **error) { GString *data; gsize len; gssize ret; gchar *pos; data = g_string_new (""); for (;;) { len = data->len; g_string_set_size (data, len + 256); ret = read (fd, data->str + len, 256); if (ret < 0) { if (errno != EAGAIN) { g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "Couldn't read from mock service: %s", g_strerror (errno)); g_string_free (data, TRUE); return NULL; } } else if (ret == 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Remote closed the output"); g_string_free (data, TRUE); return NULL; } else { data->len = len + ret; data->str[data->len] = '\0'; } pos = strchr (data->str, '\n'); if (pos) { g_string_set_size (data, pos - data->str); break; } } return g_string_free (data, FALSE); } static const gchar * service_start (const gchar *mock_script, GError **error) { GSpawnFlags flags; gboolean ret; gint output; gchar *argv[] = { "python3", (gchar *)mock_script, NULL }; g_return_val_if_fail (mock_script != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_free (service_name); service_name = NULL; flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD; ret = g_spawn_async_with_pipes (SRCDIR, argv, NULL, flags, on_python_child_setup, NULL, &pid, NULL, &output, NULL, error); if (ret) { service_name = read_until_end (output, error); if (service_name) { g_strstrip (service_name); g_assert_cmpstr (service_name, !=, ""); g_setenv ("SECRET_SERVICE_BUS_NAME", service_name, TRUE); } close (output); } return service_name; } const gchar * mock_service_start (const gchar *mock_script, GError **error) { gchar *path; const gchar *name; path = g_build_filename (SRCDIR, "libsecret", mock_script, NULL); name = service_start (path, error); g_free (path); return name; } void mock_service_stop (void) { while (g_main_context_iteration (NULL, FALSE)); if (pid) { if (kill (pid, SIGTERM) < 0) { if (errno != ESRCH) g_warning ("kill() failed: %s", g_strerror (errno)); } g_spawn_close_pid (pid); pid = 0; } while (g_main_context_iteration (NULL, FALSE)); g_unsetenv ("SECRET_SERVICE_BUS_NAME"); } 07070100000052000081A400000000000000000000000167D9F0D9000002CB000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/mock-service.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #ifndef _MOCK_SERVICE_H_ #define _MOCK_SERVICE_H_ #include const gchar * mock_service_start (const gchar *mock_script, GError **error); void mock_service_stop (void); #endif /* _MOCK_SERVICE_H_ */ 07070100000053000081A400000000000000000000000167D9F0D9000001DE000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/mock/__init__.py# # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # from .service import SecretItem, SecretCollection, SecretService, SecretPrompt from .service import PlainAlgorithm, NotSupported 07070100000054000081A400000000000000000000000167D9F0D9000064C0000000000000000000000000000000000000002700000000libsecret-0.21.7/libsecret/mock/aes.py#!/usr/bin/python # # aes.py: implements AES - Advanced Encryption Standard # from the SlowAES project, http://code.google.com/p/slowaes/ # # Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ), # Alex Martelli ( http://www.aleax.it ) # # Ported from C code written by Laurent Haan ( http://www.progressive-coding.com ) # # Licensed under the Apache License, Version 2.0 # http://www.apache.org/licenses/ # import math def append_PKCS7_padding(s): """return s padded to a multiple of 16-bytes by PKCS7 padding""" numpads = 16 - (len(s)%16) return s + bytes([numpads] * numpads) def strip_PKCS7_padding(s): """return s stripped of PKCS7 padding""" if len(s)%16 or not s: raise ValueError("String of len %d can't be PCKS7-padded" % len(s)) numpads = s[-1] if numpads > 16: raise ValueError("String ending with %r can't be PCKS7-padded" % s[-1]) return s[:-numpads] class AES(object): # valid key sizes keySize = dict(SIZE_128=16, SIZE_192=24, SIZE_256=32) # Rijndael S-box sbox = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16] # Rijndael Inverted S-box rsbox = [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb , 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb , 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e , 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 , 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 , 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 , 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 , 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b , 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 , 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e , 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b , 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 , 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f , 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef , 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 , 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d] def getSBoxValue(self,num): """Retrieves a given S-Box Value""" return self.sbox[num] def getSBoxInvert(self,num): """Retrieves a given Inverted S-Box Value""" return self.rsbox[num] def rotate(self, word): """ Rijndael's key schedule rotate operation. Rotate a word eight bits to the left: eg, rotate(1d2c3a4f) == 2c3a4f1d Word is an char list of size 4 (32 bits overall). """ return word[1:] + word[:1] # Rijndael Rcon Rcon = [0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb ] def getRconValue(self, num): """Retrieves a given Rcon Value""" return self.Rcon[num] def core(self, word, iteration): """Key schedule core.""" # rotate the 32-bit word 8 bits to the left word = self.rotate(word) # apply S-Box substitution on all 4 parts of the 32-bit word for i in range(4): word[i] = self.getSBoxValue(word[i]) # XOR the output of the rcon operation with i to the first part # (leftmost) only word[0] = word[0] ^ self.getRconValue(iteration) return word def expandKey(self, key, size, expandedKeySize): """Rijndael's key expansion. Expands an 128,192,256 key into an 176,208,240 bytes key expandedKey is a char list of large enough size, key is the non-expanded key. """ # current expanded keySize, in bytes currentSize = 0 rconIteration = 1 expandedKey = [0] * expandedKeySize # set the 16, 24, 32 bytes of the expanded key to the input key for j in range(size): expandedKey[j] = key[j] currentSize += size while currentSize < expandedKeySize: # assign the previous 4 bytes to the temporary value t t = expandedKey[currentSize-4:currentSize] # every 16,24,32 bytes we apply the core schedule to t # and increment rconIteration afterwards if currentSize % size == 0: t = self.core(t, rconIteration) rconIteration += 1 # For 256-bit keys, we add an extra sbox to the calculation if size == self.keySize["SIZE_256"] and ((currentSize % size) == 16): for l in range(4): t[l] = self.getSBoxValue(t[l]) # We XOR t with the four-byte block 16,24,32 bytes before the new # expanded key. This becomes the next four bytes in the expanded # key. for m in range(4): expandedKey[currentSize] = expandedKey[currentSize - size] ^ \ t[m] currentSize += 1 return expandedKey def addRoundKey(self, state, roundKey): """Adds (XORs) the round key to the state.""" for i in range(16): state[i] ^= roundKey[i] return state def createRoundKey(self, expandedKey, roundKeyPointer): """Create a round key. Creates a round key from the given expanded key and the position within the expanded key. """ roundKey = [0] * 16 for i in range(4): for j in range(4): roundKey[j*4+i] = expandedKey[roundKeyPointer + i*4 + j] return roundKey def galois_multiplication(self, a, b): """Galois multiplication of 8 bit characters a and b.""" p = 0 for counter in range(8): if b & 1: p ^= a hi_bit_set = a & 0x80 a <<= 1 # keep a 8 bit a &= 0xFF if hi_bit_set: a ^= 0x1b b >>= 1 return p # # substitute all the values from the state with the value in the SBox # using the state value as index for the SBox # def subBytes(self, state, isInv): if isInv: getter = self.getSBoxInvert else: getter = self.getSBoxValue for i in range(16): state[i] = getter(state[i]) return state # iterate over the 4 rows and call shiftRow() with that row def shiftRows(self, state, isInv): for i in range(4): state = self.shiftRow(state, i*4, i, isInv) return state # each iteration shifts the row to the left by 1 def shiftRow(self, state, statePointer, nbr, isInv): for i in range(nbr): if isInv: state[statePointer:statePointer+4] = \ state[statePointer+3:statePointer+4] + \ state[statePointer:statePointer+3] else: state[statePointer:statePointer+4] = \ state[statePointer+1:statePointer+4] + \ state[statePointer:statePointer+1] return state # galois multiplication of the 4x4 matrix def mixColumns(self, state, isInv): # iterate over the 4 columns for i in range(4): # construct one column by slicing over the 4 rows column = state[i:i+16:4] # apply the mixColumn on one column column = self.mixColumn(column, isInv) # put the values back into the state state[i:i+16:4] = column return state # galois multiplication of 1 column of the 4x4 matrix def mixColumn(self, column, isInv): if isInv: mult = [14, 9, 13, 11] else: mult = [2, 1, 1, 3] cpy = list(column) g = self.galois_multiplication column[0] = g(cpy[0], mult[0]) ^ g(cpy[3], mult[1]) ^ \ g(cpy[2], mult[2]) ^ g(cpy[1], mult[3]) column[1] = g(cpy[1], mult[0]) ^ g(cpy[0], mult[1]) ^ \ g(cpy[3], mult[2]) ^ g(cpy[2], mult[3]) column[2] = g(cpy[2], mult[0]) ^ g(cpy[1], mult[1]) ^ \ g(cpy[0], mult[2]) ^ g(cpy[3], mult[3]) column[3] = g(cpy[3], mult[0]) ^ g(cpy[2], mult[1]) ^ \ g(cpy[1], mult[2]) ^ g(cpy[0], mult[3]) return column # applies the 4 operations of the forward round in sequence def aes_round(self, state, roundKey): state = self.subBytes(state, False) state = self.shiftRows(state, False) state = self.mixColumns(state, False) state = self.addRoundKey(state, roundKey) return state # applies the 4 operations of the inverse round in sequence def aes_invRound(self, state, roundKey): state = self.shiftRows(state, True) state = self.subBytes(state, True) state = self.addRoundKey(state, roundKey) state = self.mixColumns(state, True) return state # Perform the initial operations, the standard round, and the final # operations of the forward aes, creating a round key for each round def aes_main(self, state, expandedKey, nbrRounds): state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0)) i = 1 while i < nbrRounds: state = self.aes_round(state, self.createRoundKey(expandedKey, 16*i)) i += 1 state = self.subBytes(state, False) state = self.shiftRows(state, False) state = self.addRoundKey(state, self.createRoundKey(expandedKey, 16*nbrRounds)) return state # Perform the initial operations, the standard round, and the final # operations of the inverse aes, creating a round key for each round def aes_invMain(self, state, expandedKey, nbrRounds): state = self.addRoundKey(state, self.createRoundKey(expandedKey, 16*nbrRounds)) i = nbrRounds - 1 while i > 0: state = self.aes_invRound(state, self.createRoundKey(expandedKey, 16*i)) i -= 1 state = self.shiftRows(state, True) state = self.subBytes(state, True) state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0)) return state # encrypts a 128 bit input block against the given key of size specified def encrypt(self, iput, key, size): output = [0] * 16 # the number of rounds nbrRounds = 0 # the 128 bit block to encode block = [0] * 16 # set the number of rounds if size == self.keySize["SIZE_128"]: nbrRounds = 10 elif size == self.keySize["SIZE_192"]: nbrRounds = 12 elif size == self.keySize["SIZE_256"]: nbrRounds = 14 else: return None # the expanded keySize expandedKeySize = 16*(nbrRounds+1) # Set the block values, for the block: # a0,0 a0,1 a0,2 a0,3 # a1,0 a1,1 a1,2 a1,3 # a2,0 a2,1 a2,2 a2,3 # a3,0 a3,1 a3,2 a3,3 # the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 # # iterate over the columns for i in range(4): # iterate over the rows for j in range(4): block[(i+(j*4))] = iput[(i*4)+j] # expand the key into an 176, 208, 240 bytes key # the expanded key expandedKey = self.expandKey(key, size, expandedKeySize) # encrypt the block using the expandedKey block = self.aes_main(block, expandedKey, nbrRounds) # unmap the block again into the output for k in range(4): # iterate over the rows for l in range(4): output[(k*4)+l] = block[(k+(l*4))] return output # decrypts a 128 bit input block against the given key of size specified def decrypt(self, iput, key, size): output = [0] * 16 # the number of rounds nbrRounds = 0 # the 128 bit block to decode block = [0] * 16 # set the number of rounds if size == self.keySize["SIZE_128"]: nbrRounds = 10 elif size == self.keySize["SIZE_192"]: nbrRounds = 12 elif size == self.keySize["SIZE_256"]: nbrRounds = 14 else: return None # the expanded keySize expandedKeySize = 16*(nbrRounds+1) # Set the block values, for the block: # a0,0 a0,1 a0,2 a0,3 # a1,0 a1,1 a1,2 a1,3 # a2,0 a2,1 a2,2 a2,3 # a3,0 a3,1 a3,2 a3,3 # the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 # iterate over the columns for i in range(4): # iterate over the rows for j in range(4): block[(i+(j*4))] = iput[(i*4)+j] # expand the key into an 176, 208, 240 bytes key expandedKey = self.expandKey(key, size, expandedKeySize) # decrypt the block using the expandedKey block = self.aes_invMain(block, expandedKey, nbrRounds) # unmap the block again into the output for k in range(4): # iterate over the rows for l in range(4): output[(k*4)+l] = block[(k+(l*4))] return output class AESModeOfOperation(object): aes = AES() # structure of supported modes of operation modeOfOperation = dict(OFB=0, CFB=1, CBC=2) # converts a 16 character string into a number array def convertString(self, string, start, end, mode): if end - start > 16: end = start + 16 if mode == self.modeOfOperation["CBC"]: ar = [0] * 16 else: ar = [] i = start j = 0 while len(ar) < end - start: ar.append(0) while i < end: ar[j] = string[i] j += 1 i += 1 return ar # Mode of Operation Encryption # stringIn - Input String # mode - mode of type modeOfOperation # hexKey - a hex key of the bit length size # size - the bit length of the key # hexIV - the 128 bit hex Initilization Vector def encrypt(self, stringIn, mode, key, size, IV): if len(key) % size: return None if len(IV) % 16: return None # the AES input/output plaintext = [] iput = [0] * 16 output = [] ciphertext = [0] * 16 # the output cipher string cipherOut = [] # char firstRound firstRound = True if stringIn != None: for j in range(int(math.ceil(float(len(stringIn))/16))): start = j*16 end = j*16+16 if end > len(stringIn): end = len(stringIn) plaintext = self.convertString(stringIn, start, end, mode) # print 'PT@%s:%s' % (j, plaintext) if mode == self.modeOfOperation["CFB"]: if firstRound: output = self.aes.encrypt(IV, key, size) firstRound = False else: output = self.aes.encrypt(iput, key, size) for i in range(16): if len(plaintext)-1 < i: ciphertext[i] = 0 ^ output[i] elif len(output)-1 < i: ciphertext[i] = plaintext[i] ^ 0 elif len(plaintext)-1 < i and len(output) < i: ciphertext[i] = 0 ^ 0 else: ciphertext[i] = plaintext[i] ^ output[i] for k in range(end-start): cipherOut.append(ciphertext[k]) iput = ciphertext elif mode == self.modeOfOperation["OFB"]: if firstRound: output = self.aes.encrypt(IV, key, size) firstRound = False else: output = self.aes.encrypt(iput, key, size) for i in range(16): if len(plaintext)-1 < i: ciphertext[i] = 0 ^ output[i] elif len(output)-1 < i: ciphertext[i] = plaintext[i] ^ 0 elif len(plaintext)-1 < i and len(output) < i: ciphertext[i] = 0 ^ 0 else: ciphertext[i] = plaintext[i] ^ output[i] for k in range(end-start): cipherOut.append(ciphertext[k]) iput = output elif mode == self.modeOfOperation["CBC"]: for i in range(16): if firstRound: iput[i] = plaintext[i] ^ IV[i] else: iput[i] = plaintext[i] ^ ciphertext[i] # print 'IP@%s:%s' % (j, iput) firstRound = False ciphertext = self.aes.encrypt(iput, key, size) # always 16 bytes because of the padding for CBC for k in range(16): cipherOut.append(ciphertext[k]) return mode, len(stringIn), cipherOut # Mode of Operation Decryption # cipherIn - Encrypted String # originalsize - The unencrypted string length - required for CBC # mode - mode of type modeOfOperation # key - a number array of the bit length size # size - the bit length of the key # IV - the 128 bit number array Initilization Vector def decrypt(self, cipherIn, originalsize, mode, key, size, IV): # cipherIn = unescCtrlChars(cipherIn) if len(key) % size: return None if len(IV) % 16: return None # the AES input/output ciphertext = [] iput = [] output = [] plaintext = [0] * 16 # the output plain text string result = [] # char firstRound firstRound = True if cipherIn != None: for j in range(int(math.ceil(float(len(cipherIn))/16))): start = j*16 end = j*16+16 if j*16+16 > len(cipherIn): end = len(cipherIn) ciphertext = cipherIn[start:end] if mode == self.modeOfOperation["CFB"]: if firstRound: output = self.aes.encrypt(IV, key, size) firstRound = False else: output = self.aes.encrypt(iput, key, size) for i in range(16): if len(output)-1 < i: plaintext[i] = 0 ^ ciphertext[i] elif len(ciphertext)-1 < i: plaintext[i] = output[i] ^ 0 elif len(output)-1 < i and len(ciphertext) < i: plaintext[i] = 0 ^ 0 else: plaintext[i] = output[i] ^ ciphertext[i] for k in range(end-start): result.append(plaintext[k]) iput = ciphertext elif mode == self.modeOfOperation["OFB"]: if firstRound: output = self.aes.encrypt(IV, key, size) firstRound = False else: output = self.aes.encrypt(iput, key, size) for i in range(16): if len(output)-1 < i: plaintext[i] = 0 ^ ciphertext[i] elif len(ciphertext)-1 < i: plaintext[i] = output[i] ^ 0 elif len(output)-1 < i and len(ciphertext) < i: plaintext[i] = 0 ^ 0 else: plaintext[i] = output[i] ^ ciphertext[i] for k in range(end-start): result.append(plaintext[k]) iput = output elif mode == self.modeOfOperation["CBC"]: output = self.aes.decrypt(ciphertext, key, size) for i in range(16): if firstRound: plaintext[i] = IV[i] ^ output[i] else: plaintext[i] = iput[i] ^ output[i] firstRound = False if originalsize is not None and originalsize < end: for k in range(originalsize-start): result.append(plaintext[k]) else: for k in range(end-start): result.append(plaintext[k]) iput = ciphertext return bytes(result) if __name__ == "__main__": moo = AESModeOfOperation() cleartext = "This is a test!" cypherkey = [143,194,34,208,145,203,230,143,177,246,97,206,145,92,255,84] iv = [103,35,148,239,76,213,47,118,255,222,123,176,106,134,98,92] mode, orig_len, ciph = moo.encrypt(cleartext, moo.modeOfOperation["CBC"], cypherkey, moo.aes.keySize["SIZE_128"], iv) print('m=%s, ol=%s (%s), ciph=%s' % (mode, orig_len, len(cleartext), ciph)) decr = moo.decrypt(ciph, orig_len, mode, cypherkey, moo.aes.keySize["SIZE_128"], iv) print(decr) 07070100000055000081A400000000000000000000000167D9F0D900000713000000000000000000000000000000000000002600000000libsecret-0.21.7/libsecret/mock/dh.py # WARNING: This is for use in mock objects during testing, and NOT # cryptographically secure or performant. # # Copyright 2011 Stef Walter # # 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 of the licence or (at # your option) any later version. # # See the included COPYING file for more information. # # # Some utility functions from tlslite which is public domain # Written by Trevor Perrin # http://trevp.net/tlslite/ # import math import random PRIME = b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1' \ b'\x29\x02\x4E\x08\x8A\x67\xCC\x74\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD' \ b'\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\x4F\xE1\x35\x6D\x6D\x51\xC2\x45' \ b'\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\xF4\x4C\x42\xE9\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED' \ b'\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\x49\x28\x66\x51\xEC\xE6\x53\x81' \ b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' def num_bytes(number): return math.ceil(number.bit_length() / 8) def number_to_bytes(number): n_data = num_bytes(number) return number.to_bytes(n_data, 'big') def generate_pair(): prime = int.from_bytes(PRIME, 'big') base = 2 # print "mock prime: ", hex(prime) # print " mock base: ", hex(base) bits = prime.bit_length() privat = 0 while privat == 0: privat = random.getrandbits(bits - 1) publi = pow(base, privat, prime) return (privat, publi) def derive_key(privat, peer): prime = int.from_bytes(PRIME, 'big') key = pow(peer, privat, prime) # print " mock ikm2: ", hex(key) return number_to_bytes(key) 07070100000056000081A400000000000000000000000167D9F0D9000008DF000000000000000000000000000000000000002800000000libsecret-0.21.7/libsecret/mock/hkdf.py # Upstream Author: Zooko O'Whielacronx # # Copyright: # # You may use this package under the GNU General Public License, version # 2 or, at your option, any later version. You may use this package # under the Transitive Grace Period Public Licence, version 1.0 or, at # your option, any later version. (You may choose to use this package # under the terms of either licence, at your option.) See the file # COPYING.TESTS for the terms of the GNU General Public License, version 2. # # The following licensing text applies to a subset of the Crypto++ source code # which is included in the pycryptopp source tree under the "embeddedcryptopp" # subdirectory. That embedded subset of the Crypto++ source code is not used # when pycryptopp is built for Debian -- instead the --disable-embedded-cryptopp # option to "setup.py build" is used to for pycryptopp to build against the # system libcryptopp. import hashlib, hmac class HKDF(object): def __init__(self, ikm, L, salt=None, info=None, digestmod = None): self.ikm = ikm self.keylen = L if digestmod is None: digestmod = hashlib.sha256 if callable(digestmod): self.digest_cons = digestmod else: self.digest_cons = lambda d='':digestmod.new(d) self.hashlen = len(self.digest_cons().digest()) if salt is None: self.salt = b'\x00' * (self.hashlen) else: self.salt = salt self.info = info or b'' #extract PRK def extract(self): h = hmac.new(self.salt, self.ikm, self.digest_cons) self.prk = h.digest() return self.prk #expand PRK def expand(self): T = b"" temp = b"" i=0x01 while len(T) 07070100000059000081A400000000000000000000000167D9F0D90000256A000000000000000000000000000000000000002F00000000libsecret-0.21.7/libsecret/secret-attributes.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-attributes.h" #include "secret-private.h" #include GVariant * _secret_attributes_to_variant (GHashTable *attributes, const gchar *schema_name) { GHashTableIter iter; GVariantBuilder builder; const gchar *name; const gchar *value; g_return_val_if_fail (attributes != NULL, NULL); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); g_hash_table_iter_init (&iter, attributes); while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&value)) { if (!schema_name || !g_str_equal (name, "xdg:schema")) g_variant_builder_add (&builder, "{ss}", name, value); } if (schema_name) g_variant_builder_add (&builder, "{ss}", "xdg:schema", schema_name); return g_variant_builder_end (&builder); } GHashTable * _secret_attributes_for_variant (GVariant *variant) { GVariantIter iter; GHashTable *attributes; gchar *value; gchar *key; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_variant_iter_init (&iter, variant); while (g_variant_iter_next (&iter, "{ss}", &key, &value)) g_hash_table_insert (attributes, key, value); return attributes; } /** * secret_attributes_build: (skip) * @schema: the schema for the attributes * @...: the attribute keys and values, terminated with %NULL * * Build up a hash table of attribute values. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attributes should be terminated with a %NULL. * * Returns: (transfer full) (element-type utf8 utf8): a new table of * attributes, to be released with [func@GLib.HashTable.unref] */ GHashTable * secret_attributes_build (const SecretSchema *schema, ...) { GHashTable *attributes; va_list va; va_start (va, schema); attributes = secret_attributes_buildv (schema, va); va_end (va); return attributes; } /** * secret_attributes_buildv: (skip) * @schema: the schema for the attributes * @va: the attribute keys and values, terminated with %NULL * * Build up a hash table of attribute values. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attributes should be terminated with a %NULL. * * Returns: (transfer full) (element-type utf8 utf8): a new table of * attributes, to be released with [func@GLib.HashTable.unref] */ GHashTable * secret_attributes_buildv (const SecretSchema *schema, va_list va) { const gchar *attribute_name; SecretSchemaAttributeType type; GHashTable *attributes; const gchar *string; gboolean type_found; gchar *value = NULL; gboolean boolean; gint integer; gint i; g_return_val_if_fail (schema != NULL, NULL); attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); for (;;) { attribute_name = va_arg (va, const gchar *); if (attribute_name == NULL) break; type_found = FALSE; for (i = 0; i < G_N_ELEMENTS (schema->attributes); ++i) { if (!schema->attributes[i].name) break; if (g_str_equal (schema->attributes[i].name, attribute_name)) { type_found = TRUE; type = schema->attributes[i].type; break; } } if (!type_found) { g_critical ("The attribute '%s' was not found in the password schema.", attribute_name); g_hash_table_unref (attributes); return NULL; } switch (type) { case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN: boolean = va_arg (va, gboolean); value = g_strdup (boolean ? "true" : "false"); break; case SECRET_SCHEMA_ATTRIBUTE_STRING: string = va_arg (va, gchar *); if (string == NULL) { g_critical ("The value for attribute '%s' was NULL", attribute_name); return NULL; } if (!g_utf8_validate (string, -1, NULL)) { g_critical ("The value for attribute '%s' was not a valid UTF-8 string.", attribute_name); g_hash_table_unref (attributes); return NULL; } value = g_strdup (string); break; case SECRET_SCHEMA_ATTRIBUTE_INTEGER: integer = va_arg (va, gint); value = g_strdup_printf ("%d", integer); break; default: g_critical ("The password attribute '%s' has an invalid type in the password schema.", attribute_name); g_hash_table_unref (attributes); return NULL; } g_hash_table_insert (attributes, g_strdup (attribute_name), value); } return attributes; } /** * secret_attributes_validate: * @schema: the schema for the attributes * @attributes: the attributes to be validated * @error: place to report errors encountered * * Check if attributes are valid according to the provided schema. * * Verifies schema name if available, attribute names and parsing * of attribute values. * * Returns: whether or not the given attributes table is valid * * Since: 0.21.2 */ gboolean secret_attributes_validate (const SecretSchema *schema, GHashTable *attributes, GError **error) { const SecretSchemaAttribute *attribute; GHashTableIter iter; gboolean any = FALSE; gchar *key; gchar *value; gchar *end; gint i; g_return_val_if_fail (schema != NULL, FALSE); g_hash_table_iter_init (&iter, attributes); while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) { any = TRUE; /* If the 'xdg:schema' meta-attribute is present, ensure that it is consistent with the schema name. */ if (g_str_equal (key, "xdg:schema")) { if (!g_str_equal (value, schema->name)) { g_set_error_literal (error, SECRET_ERROR, SECRET_ERROR_MISMATCHED_SCHEMA, "Schema attribute doesn't match schema name"); return FALSE; } continue; } /* Pass through libgnomekeyring specific attributes */ if (g_str_has_prefix (key, "gkr:")) continue; /* Find the attribute */ attribute = NULL; for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) { if (schema->attributes[i].name == NULL) break; if (g_str_equal (schema->attributes[i].name, key)) { attribute = &schema->attributes[i]; break; } } if (attribute == NULL) { g_set_error (error, SECRET_ERROR, SECRET_ERROR_NO_MATCHING_ATTRIBUTE, "Schema does not contain any attributes matching %s", key); return FALSE; } switch (attribute->type) { case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN: if (!g_str_equal (value, "true") && !g_str_equal (value, "false")) { g_set_error (error, SECRET_ERROR, SECRET_ERROR_WRONG_TYPE, "Attribute %s could not be parsed into a boolean", key); return FALSE; } break; case SECRET_SCHEMA_ATTRIBUTE_INTEGER: end = NULL; g_ascii_strtoll (value, &end, 10); if (!end || end[0] != '\0') { g_set_error (error, SECRET_ERROR, SECRET_ERROR_WRONG_TYPE, "Attribute %s could not be parsed into an integer", key); return FALSE; } break; case SECRET_SCHEMA_ATTRIBUTE_STRING: if (!g_utf8_validate (value, -1, NULL)) { g_set_error (error, SECRET_ERROR, SECRET_ERROR_WRONG_TYPE, "Attribute %s could not be parsed into a string", key); return FALSE; } break; default: g_set_error (error, SECRET_ERROR, SECRET_ERROR_WRONG_TYPE, "%s: Invalid attribute type", key); return FALSE; } } /* Nothing to match on, resulting search would match everything :S */ if (!any && schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME) { g_set_error_literal (error, SECRET_ERROR, SECRET_ERROR_EMPTY_TABLE, "Must have at least one attribute to check"); return FALSE; } return TRUE; } // Private function to be used internally gboolean _secret_attributes_validate (const SecretSchema *schema, GHashTable *attributes, const char *pretty_function, gboolean matching) { GError *error = NULL; if (!secret_attributes_validate (schema, attributes, &error)) { // if matching is false, an empty table is fine if ((!matching) && (error->code == SECRET_ERROR_EMPTY_TABLE)) { g_error_free (error); return TRUE; } g_warning ("%s: error validating schema: %s", pretty_function, error->message); g_error_free (error); return FALSE; } return TRUE; } GHashTable * _secret_attributes_copy (GHashTable *attributes) { GHashTableIter iter; GHashTable *copy; gchar *key; gchar *value; if (attributes == NULL) return NULL; copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_iter_init (&iter, attributes); while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) g_hash_table_insert (copy, g_strdup (key), g_strdup (value)); return copy; } 0707010000005A000081A400000000000000000000000167D9F0D9000004E8000000000000000000000000000000000000002F00000000libsecret-0.21.7/libsecret/secret-attributes.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_ATTRIBUTES_H__ #define __SECRET_ATTRIBUTES_H__ #include #include #include "secret-schema.h" G_BEGIN_DECLS GHashTable * secret_attributes_build (const SecretSchema *schema, ...) G_GNUC_NULL_TERMINATED; GHashTable * secret_attributes_buildv (const SecretSchema *schema, va_list va); gboolean secret_attributes_validate (const SecretSchema *schema, GHashTable *attributes, GError **error); G_END_DECLS #endif /* __SECRET_ATTRIBUTES_H___ */ 0707010000005B000081A400000000000000000000000167D9F0D90000205C000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/secret-backend.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #include "config.h" #include "secret-backend.h" #ifdef WITH_CRYPTO #include "secret-file-backend.h" #endif #include "secret-private.h" #include "libsecret/secret-enum-types.h" /** * SecretBackend: * * #SecretBackend represents a backend implementation of password * storage. * * Stability: Stable * * Since: 0.19.0 */ /** * SecretBackendInterface: * @parent_iface: the parent interface * @ensure_for_flags: implementation of reinitialization step in constructor, optional * @ensure_for_flags_finish: implementation of reinitialization step in constructor, optional * @store: implementation of [func@password_store], required * @store_finish: implementation of [func@password_store_finish], required * @lookup: implementation of [func@password_lookup], required * @lookup_finish: implementation of [func@password_lookup_finish], required * @clear: implementation of [func@password_clear], required * @clear_finish: implementation of [func@password_clear_finish], required * @search: implementation of [func@password_search], required * @search_finish: implementation of [func@password_search_finish], required * * The interface for #SecretBackend. * * Since: 0.19.0 */ /** * SecretBackendFlags: * @SECRET_BACKEND_NONE: no flags for initializing the #SecretBackend * @SECRET_BACKEND_OPEN_SESSION: establish a session for transfer of secrets * while initializing the #SecretBackend * @SECRET_BACKEND_LOAD_COLLECTIONS: load collections while initializing the * #SecretBackend * * Flags which determine which parts of the #SecretBackend are initialized. * * Since: 0.19.0 */ /** * SECRET_BACKEND_EXTENSION_POINT_NAME: * * Extension point for the secret backend. */ G_DEFINE_INTERFACE_WITH_CODE (SecretBackend, secret_backend, G_TYPE_OBJECT, g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_ASYNC_INITABLE); ); static void secret_backend_default_init (SecretBackendInterface *iface) { /** * SecretBackend:flags: * * A set of flags describing which parts of the secret backend have * been initialized. * * Since: 0.19.0 */ g_object_interface_install_property (iface, g_param_spec_flags ("flags", "Flags", "Service flags", secret_service_flags_get_type (), SECRET_SERVICE_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } void _secret_backend_ensure_extension_point (void) { GIOExtensionPoint *ep; static gboolean registered = FALSE; if (registered) return; ep = g_io_extension_point_register (SECRET_BACKEND_EXTENSION_POINT_NAME); g_io_extension_point_set_required_type (ep, SECRET_TYPE_BACKEND); registered = TRUE; } G_LOCK_DEFINE (backend_instance); static gpointer backend_instance = NULL; static SecretBackend * backend_get_instance (void) { SecretBackend *instance = NULL; G_LOCK (backend_instance); if (backend_instance != NULL) instance = g_object_ref (backend_instance); G_UNLOCK (backend_instance); return instance; } void _secret_backend_uncache_instance (void) { SecretBackend *instance = NULL; G_LOCK (backend_instance); instance = backend_instance; backend_instance = NULL; G_UNLOCK (backend_instance); if (instance != NULL) g_object_unref (instance); } static GType backend_get_impl_type (void) { const gchar *envvar; const gchar *extension_name; GIOExtension *e; GIOExtensionPoint *ep; g_type_ensure (secret_service_get_type ()); #ifdef WITH_CRYPTO g_type_ensure (secret_file_backend_get_type ()); #endif #ifdef WITH_CRYPTO if ((g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS) || g_getenv ("SNAP_NAME") != NULL) && _secret_file_backend_check_portal_version ()) extension_name = "file"; else #endif { envvar = g_getenv ("SECRET_BACKEND"); if (envvar == NULL || *envvar == '\0') extension_name = "service"; else extension_name = envvar; } ep = g_io_extension_point_lookup (SECRET_BACKEND_EXTENSION_POINT_NAME); e = g_io_extension_point_get_extension_by_name (ep, extension_name); if (e == NULL) { g_warning ("Backend extension \"%s\" from SECRET_BACKEND_EXTENSION_POINT_NAME environment variable not found.", extension_name); return G_TYPE_NONE; } return g_io_extension_get_type (e); } static void on_ensure_for_flags (GObject *source_object, GAsyncResult *result, gpointer user_data) { SecretBackendInterface *iface; SecretBackend *self = SECRET_BACKEND (source_object); GTask *task = G_TASK (user_data); GError *error = NULL; iface = SECRET_BACKEND_GET_IFACE (self); if (iface->ensure_for_flags_finish) { if (!iface->ensure_for_flags_finish (self, result, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } } g_task_return_boolean (task, TRUE); g_object_unref (task); } /** * secret_backend_get: * @flags: flags for which service functionality to ensure is initialized * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Get a #SecretBackend instance. * * If such a backend already exists, then the same backend is returned. * * If @flags contains any flags of which parts of the secret backend to * ensure are initialized, then those will be initialized before completing. * * This method will return immediately and complete asynchronously. * * Since: 0.19.0 */ void secret_backend_get (SecretBackendFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretBackend *backend = NULL; SecretBackendInterface *iface; GTask *task; backend = backend_get_instance (); /* Create a whole new backend */ if (backend == NULL) { GType impl_type = backend_get_impl_type (); g_return_if_fail (g_type_is_a (impl_type, G_TYPE_ASYNC_INITABLE)); g_async_initable_new_async (impl_type, G_PRIORITY_DEFAULT, cancellable, callback, user_data, "flags", flags, NULL); /* Just have to ensure that the backend matches flags */ } else { task = g_task_new (backend, cancellable, callback, user_data); iface = SECRET_BACKEND_GET_IFACE (backend); if (iface->ensure_for_flags) { g_task_set_source_tag (task, secret_backend_get); iface->ensure_for_flags (backend, flags, cancellable, on_ensure_for_flags, task); } else { g_task_return_boolean (task, TRUE); g_object_unref (task); } g_object_unref (backend); } } /** * secret_backend_get_finish: * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Complete an asynchronous operation to get a #SecretBackend. * * Returns: (transfer full): a new reference to a #SecretBackend proxy, which * should be released with [method@GObject.Object.unref]. * * Since: 0.19.0 */ SecretBackend * secret_backend_get_finish (GAsyncResult *result, GError **error) { GTask *task; GObject *backend = NULL; GObject *source_object; g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); task = G_TASK (result); source_object = g_task_get_source_object (task); g_return_val_if_fail (g_task_is_valid (result, source_object), NULL); /* Just ensuring that the backend matches flags */ if (g_task_get_source_tag (task) == secret_backend_get) { if (g_task_had_error (task)) { g_task_propagate_pointer (task, error); } else { backend = g_object_ref (source_object); } /* Creating a whole new backend */ } else { backend = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error); if (backend) { G_LOCK (backend_instance); if (backend_instance == NULL) backend_instance = backend; G_UNLOCK (backend_instance); } } if (backend == NULL) return NULL; return SECRET_BACKEND (backend); } 0707010000005C000081A400000000000000000000000167D9F0D9000014AE000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/secret-backend.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_BACKEND_H__ #define __SECRET_BACKEND_H__ #include #include "secret-schema.h" #include "secret-service.h" #include "secret-value.h" G_BEGIN_DECLS typedef enum { SECRET_BACKEND_NONE = SECRET_SERVICE_NONE, SECRET_BACKEND_OPEN_SESSION = SECRET_SERVICE_OPEN_SESSION, SECRET_BACKEND_LOAD_COLLECTIONS = SECRET_SERVICE_LOAD_COLLECTIONS, } SecretBackendFlags; #define SECRET_TYPE_BACKEND secret_backend_get_type () G_DECLARE_INTERFACE (SecretBackend, secret_backend, SECRET, BACKEND, GObject) struct _SecretBackendInterface { GTypeInterface parent_iface; void (*ensure_for_flags) (SecretBackend *self, SecretBackendFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean (*ensure_for_flags_finish) (SecretBackend *self, GAsyncResult *result, GError **error); void (*store) (SecretBackend *self, const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean (*store_finish) (SecretBackend *self, GAsyncResult *result, GError **error); void (*lookup) (SecretBackend *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretValue *(*lookup_finish) (SecretBackend *self, GAsyncResult *result, GError **error); void (*clear) (SecretBackend *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean (*clear_finish) (SecretBackend *self, GAsyncResult *result, GError **error); void (*search) (SecretBackend *self, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GList * (*search_finish) (SecretBackend *self, GAsyncResult *result, GError **error); }; #define SECRET_BACKEND_EXTENSION_POINT_NAME "secret-backend" void _secret_backend_ensure_extension_point (void); void _secret_backend_uncache_instance (void); void secret_backend_get (SecretBackendFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretBackend *secret_backend_get_finish (GAsyncResult *result, GError **error); G_END_DECLS #endif /* __SECRET_BACKEND_H__ */ 0707010000005D000081A400000000000000000000000167D9F0D900010EAD000000000000000000000000000000000000002F00000000libsecret-0.21.7/libsecret/secret-collection.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-collection.h" #include "secret-dbus-generated.h" #include "secret-item.h" #include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "secret-types.h" #include "libsecret/secret-enum-types.h" #include /** * SecretCollection: * * A proxy object representing a collection of secrets in the Secret Service. * * #SecretCollection represents a collection of secret items stored in the * Secret Service. * * A collection can be in a locked or unlocked state. Use * [method@SecretService.lock] or [method@SecretService.unlock] to lock or * unlock the collection. * * Use the [property@SecretCollection:items] property or * [method@SecretCollection.get_items] to lookup the items in the collection. * There may not be any items exposed when the collection is locked. * * Stability: Stable */ /** * SecretCollectionClass: * @parent_class: the parent class * * The class for #SecretCollection. */ /** * SecretCollectionFlags: * @SECRET_COLLECTION_NONE: no flags * @SECRET_COLLECTION_LOAD_ITEMS: items have or should be loaded * * Flags which determine which parts of the #SecretCollection proxy are initialized. */ /** * SecretCollectionCreateFlags: * @SECRET_COLLECTION_CREATE_NONE: no flags * * Flags for [func@Collection.create]. */ /** * SECRET_COLLECTION_DEFAULT: * * An alias to the default collection. * * This can be passed to [func@password_store] [func@Collection.for_alias]. */ /** * SECRET_COLLECTION_SESSION: * * An alias to the session collection, which will be cleared when the user ends * the session. * * This can be passed to [func@password_store], [func@Collection.for_alias] or * similar functions. */ enum { PROP_0, PROP_SERVICE, PROP_FLAGS, PROP_ITEMS, PROP_LABEL, PROP_LOCKED, PROP_CREATED, PROP_MODIFIED }; struct _SecretCollectionPrivate { /* Doesn't change between construct and finalize */ SecretService *service; GCancellable *cancellable; gboolean constructing; SecretCollectionFlags init_flags; /* Protected by mutex */ GMutex mutex; GHashTable *items; }; static GInitableIface *secret_collection_initable_parent_iface = NULL; static GAsyncInitableIface *secret_collection_async_initable_parent_iface = NULL; static void secret_collection_initable_iface (GInitableIface *iface); static void secret_collection_async_initable_iface (GAsyncInitableIface *iface); G_DEFINE_TYPE_WITH_CODE (SecretCollection, secret_collection, G_TYPE_DBUS_PROXY, G_ADD_PRIVATE (SecretCollection) G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_collection_initable_iface); G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_collection_async_initable_iface); ); static GHashTable * items_table_new (void) { return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } static void secret_collection_init (SecretCollection *self) { self->pv = secret_collection_get_instance_private (self); g_mutex_init (&self->pv->mutex); self->pv->cancellable = g_cancellable_new (); self->pv->constructing = TRUE; } static void on_set_label (GObject *source, GAsyncResult *result, gpointer user_data) { SecretCollection *self = SECRET_COLLECTION (user_data); GError *error = NULL; secret_collection_set_label_finish (self, result, &error); if (error != NULL) { g_warning ("couldn't set SecretCollection Label: %s", error->message); g_error_free (error); } g_object_unref (self); } static void collection_take_service (SecretCollection *self, SecretService *service) { if (service == NULL) return; g_return_if_fail (self->pv->service == NULL); self->pv->service = service; g_object_add_weak_pointer (G_OBJECT (self->pv->service), (gpointer *)&self->pv->service); /* Yes, we expect that the service will stay around */ g_object_unref (service); } static void secret_collection_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { SecretCollection *self = SECRET_COLLECTION (obj); switch (prop_id) { case PROP_SERVICE: collection_take_service (self, g_value_dup_object (value)); break; case PROP_FLAGS: self->pv->init_flags = g_value_get_flags (value); break; case PROP_LABEL: secret_collection_set_label (self, g_value_get_string (value), self->pv->cancellable, on_set_label, g_object_ref (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void secret_collection_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { SecretCollection *self = SECRET_COLLECTION (obj); switch (prop_id) { case PROP_SERVICE: g_value_set_object (value, self->pv->service); break; case PROP_FLAGS: g_value_set_flags (value, secret_collection_get_flags (self)); break; case PROP_ITEMS: g_value_take_boxed (value, secret_collection_get_items (self)); break; case PROP_LABEL: g_value_take_string (value, secret_collection_get_label (self)); break; case PROP_LOCKED: g_value_set_boolean (value, secret_collection_get_locked (self)); break; case PROP_CREATED: g_value_set_uint64 (value, secret_collection_get_created (self)); break; case PROP_MODIFIED: g_value_set_uint64 (value, secret_collection_get_modified (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void secret_collection_dispose (GObject *obj) { SecretCollection *self = SECRET_COLLECTION (obj); g_cancellable_cancel (self->pv->cancellable); G_OBJECT_CLASS (secret_collection_parent_class)->dispose (obj); } static void secret_collection_finalize (GObject *obj) { SecretCollection *self = SECRET_COLLECTION (obj); if (self->pv->service) g_object_remove_weak_pointer (G_OBJECT (self->pv->service), (gpointer *)&self->pv->service); g_mutex_clear (&self->pv->mutex); if (self->pv->items) g_hash_table_destroy (self->pv->items); g_object_unref (self->pv->cancellable); G_OBJECT_CLASS (secret_collection_parent_class)->finalize (obj); } static void collection_update_items (SecretCollection *self, GHashTable *items) { GHashTable *previous; g_hash_table_ref (items); g_mutex_lock (&self->pv->mutex); previous = self->pv->items; self->pv->items = items; g_mutex_unlock (&self->pv->mutex); if (previous != NULL) g_hash_table_unref (previous); g_object_notify (G_OBJECT (self), "items"); } static void handle_property_changed (SecretCollection *self, const gchar *property_name, GVariant *value) { gboolean perform; if (g_str_equal (property_name, "Label")) { g_object_notify (G_OBJECT (self), "label"); } else if (g_str_equal (property_name, "Locked")) { g_object_notify (G_OBJECT (self), "locked"); } else if (g_str_equal (property_name, "Created")) { g_object_notify (G_OBJECT (self), "created"); } else if (g_str_equal (property_name, "Modified")) { g_object_notify (G_OBJECT (self), "modified"); } else if (g_str_equal (property_name, "Items") && !self->pv->constructing) { g_mutex_lock (&self->pv->mutex); perform = self->pv->items != NULL; g_mutex_unlock (&self->pv->mutex); if (perform) secret_collection_load_items (self, self->pv->cancellable, NULL, NULL); } } static void secret_collection_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, const gchar* const *invalidated_properties) { SecretCollection *self = SECRET_COLLECTION (proxy); gchar *property_name; GVariantIter iter; GVariant *value; g_object_freeze_notify (G_OBJECT (self)); g_variant_iter_init (&iter, changed_properties); while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value)) handle_property_changed (self, property_name, value); g_object_thaw_notify (G_OBJECT (self)); } static void secret_collection_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters) { SecretCollection *self = SECRET_COLLECTION (proxy); SecretItem *item; const gchar *item_path; GVariantBuilder builder; gboolean found = FALSE; GVariantIter iter; GVariant *value; GVariant *paths; GVariant *path; /* * Remember that these signals come from a time before PropertiesChanged. * We support them because they're in the spec, and ksecretservice uses them. */ paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items"); /* A new collection was added, add it to the Collections property */ if (g_str_equal (signal_name, SECRET_SIGNAL_ITEM_CREATED)) { g_variant_get (parameters, "(@o)", &value); g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao")); g_variant_iter_init (&iter, paths); while ((path = g_variant_iter_next_value (&iter)) != NULL) { if (g_variant_equal (path, value)) { found = TRUE; break; } g_variant_builder_add_value (&builder, path); g_variant_unref (path); } if (!found) { g_variant_builder_add_value (&builder, value); handle_property_changed (self, "Items", g_variant_builder_end (&builder)); } g_variant_builder_clear (&builder); g_variant_unref (value); /* A collection was deleted, remove it from the Collections property */ } else if (g_str_equal (signal_name, SECRET_SIGNAL_ITEM_DELETED)) { g_variant_get (parameters, "(@o)", &value); g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao")); g_variant_iter_init (&iter, paths); while ((path = g_variant_iter_next_value (&iter)) != NULL) { if (g_variant_equal (path, value)) found = TRUE; else g_variant_builder_add_value (&builder, path); g_variant_unref (path); } if (found) handle_property_changed (self, "Items", g_variant_builder_end (&builder)); g_variant_unref (value); /* The collection changed, update it */ } else if (g_str_equal (signal_name, SECRET_SIGNAL_ITEM_CHANGED)) { g_variant_get (parameters, "(&o)", &item_path); g_mutex_lock (&self->pv->mutex); if (self->pv->items) item = g_hash_table_lookup (self->pv->items, item_path); else item = NULL; if (item) g_object_ref (item); g_mutex_unlock (&self->pv->mutex); if (item) { secret_item_refresh (item); g_object_unref (item); } } g_variant_unref (paths); } static void secret_collection_class_init (SecretCollectionClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass); gobject_class->get_property = secret_collection_get_property; gobject_class->set_property = secret_collection_set_property; gobject_class->dispose = secret_collection_dispose; gobject_class->finalize = secret_collection_finalize; proxy_class->g_properties_changed = secret_collection_properties_changed; proxy_class->g_signal = secret_collection_signal; /** * SecretCollection:service: (attributes org.gtk.Property.get=secret_collection_get_service) * * The [class@Service] object that this collection is associated with and * uses to interact with the actual D-Bus Secret Service. */ g_object_class_install_property (gobject_class, PROP_SERVICE, g_param_spec_object ("service", "Service", "Secret Service", SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * SecretCollection:flags: (attributes org.gtk.Property.get=secret_collection_get_flags) * * A set of flags describing which parts of the secret collection have * been initialized. */ g_object_class_install_property (gobject_class, PROP_FLAGS, g_param_spec_flags ("flags", "Flags", "Collection flags", secret_collection_flags_get_type (), SECRET_COLLECTION_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * SecretCollection:items: (attributes org.gtk.Property.get=secret_collection_get_items) * * A list of [class@Item] objects representing the items that are in * this collection. This list will be empty if the collection is locked. */ g_object_class_install_property (gobject_class, PROP_ITEMS, g_param_spec_boxed ("items", "Items", "Items in collection", _secret_list_get_type (), G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * SecretCollection:label: (attributes org.gtk.Property.get=secret_collection_get_label org.gtk.Property.set=secret_collection_set_label) * * The human readable label for the collection. * * Setting this property will result in the label of the collection being * set asynchronously. To properly track the changing of the label use the * [method@Collection.set_label] function. */ g_object_class_install_property (gobject_class, PROP_LABEL, g_param_spec_string ("label", "Label", "Item label", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * SecretCollection:locked: (attributes org.gtk.Property.get=secret_collection_get_locked) * * Whether the collection is locked or not. * * To lock or unlock a collection use the [method@Service.lock] or * [method@Service.unlock] functions. */ g_object_class_install_property (gobject_class, PROP_LOCKED, g_param_spec_boolean ("locked", "Locked", "Item locked", TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * SecretCollection:created: (attributes org.gtk.Property.get=secret_collection_get_created) * * The date and time (in seconds since the UNIX epoch) that this * collection was created. */ g_object_class_install_property (gobject_class, PROP_CREATED, g_param_spec_uint64 ("created", "Created", "Item creation date", 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * SecretCollection:modified: (attributes org.gtk.Property.get=secret_collection_get_modified) * * The date and time (in seconds since the UNIX epoch) that this * collection was last modified. */ g_object_class_install_property (gobject_class, PROP_MODIFIED, g_param_spec_uint64 ("modified", "Modified", "Item modified date", 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static gboolean collection_ensure_for_flags_sync (SecretCollection *self, SecretCollectionFlags flags, GCancellable *cancellable, GError **error) { SecretCollectionFlags want_flags; want_flags = flags & ~secret_collection_get_flags (self); if (want_flags & SECRET_COLLECTION_LOAD_ITEMS) { if (!secret_collection_load_items_sync (self, cancellable, error)) return FALSE; } return TRUE; } static gboolean secret_collection_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { SecretCollection *self; SecretService *service; GDBusProxy *proxy; if (!secret_collection_initable_parent_iface->init (initable, cancellable, error)) return FALSE; proxy = G_DBUS_PROXY (initable); if (!_secret_util_have_cached_properties (proxy)) { g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "No such secret collection at path: %s", g_dbus_proxy_get_object_path (proxy)); return FALSE; } self = SECRET_COLLECTION (initable); if (self->pv->service == NULL) { service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error); if (service == NULL) return FALSE; else collection_take_service (self, service); } if (!collection_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error)) return FALSE; self->pv->constructing = FALSE; return TRUE; } static void secret_collection_initable_iface (GInitableIface *iface) { secret_collection_initable_parent_iface = g_type_interface_peek_parent (iface); iface->init = secret_collection_initable_init; } static void on_ensure_items (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretCollection *self = SECRET_COLLECTION (source); GError *error = NULL; if (!secret_collection_load_items_finish (self, result, &error)) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_pointer (task, self, g_object_unref); g_clear_object (&task); } static void collection_ensure_for_flags_async (SecretCollection *self, SecretCollectionFlags flags, GTask *task) { GCancellable *cancellable = g_task_get_cancellable (task); SecretCollectionFlags want_flags; want_flags = flags & ~secret_collection_get_flags (self); if (want_flags & SECRET_COLLECTION_LOAD_ITEMS) { secret_collection_load_items (self, cancellable, on_ensure_items, g_object_ref (task)); } else { g_task_return_pointer (task, self, g_object_unref); } } static void on_init_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretCollection *self = SECRET_COLLECTION (g_task_get_source_object (task)); SecretService *service; GError *error = NULL; service = secret_service_get_finish (result, &error); if (error == NULL) { collection_take_service (self, g_steal_pointer (&service)); collection_ensure_for_flags_async (self, self->pv->init_flags, task); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } typedef struct { GAsyncReadyCallback callback; gpointer user_data; } InitBaseClosure; static void secret_collection_async_initable_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); static void on_init_base (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *base_task = G_TASK (user_data); InitBaseClosure *base = g_task_get_task_data (base_task); GCancellable *cancellable = g_task_get_cancellable (base_task); GTask *task; SecretCollection *self = SECRET_COLLECTION (source); GDBusProxy *proxy = G_DBUS_PROXY (self); GError *error = NULL; task = g_task_new (source, cancellable, base->callback, base->user_data); g_task_set_source_tag (task, secret_collection_async_initable_init_async); g_clear_object (&base_task); if (!secret_collection_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self), result, &error)) { g_task_return_error (task, g_steal_pointer (&error)); } else if (!_secret_util_have_cached_properties (proxy)) { g_task_return_new_error (task, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "No such secret collection at path: %s", g_dbus_proxy_get_object_path (proxy)); } else if (self->pv->service == NULL) { secret_service_get (SECRET_SERVICE_NONE, cancellable, on_init_service, g_steal_pointer (&task)); } else { collection_ensure_for_flags_async (self, self->pv->init_flags, task); } g_clear_object (&task); } static void secret_collection_async_initable_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; InitBaseClosure *base; task = g_task_new (initable, cancellable, NULL, NULL); g_task_set_source_tag (task, secret_collection_async_initable_init_async); base = g_new0 (InitBaseClosure, 1); base->callback = callback; base->user_data = user_data; g_task_set_task_data (task, base, g_free); secret_collection_async_initable_parent_iface->init_async (initable, io_priority, cancellable, on_init_base, g_steal_pointer (&task)); g_clear_object (&task); } static gboolean secret_collection_async_initable_init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error) { SecretCollection *self = SECRET_COLLECTION (initable); g_return_val_if_fail (g_task_is_valid (result, initable), FALSE); // XXX maybe we still need to ref? if (!g_task_propagate_pointer (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } self->pv->constructing = FALSE; return TRUE; } static void secret_collection_async_initable_iface (GAsyncInitableIface *iface) { secret_collection_async_initable_parent_iface = g_type_interface_peek_parent (iface); iface->init_async = secret_collection_async_initable_init_async; iface->init_finish = secret_collection_async_initable_init_finish; } typedef struct { GHashTable *items; gint items_loading; } ItemsClosure; static void items_closure_free (gpointer data) { ItemsClosure *closure = data; g_hash_table_unref (closure->items); g_free (closure); } static void on_load_item (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); ItemsClosure *closure = g_task_get_task_data (task); SecretCollection *self = SECRET_COLLECTION (g_task_get_source_object (task)); const gchar *path; GError *error = NULL; SecretItem *item; closure->items_loading--; item = secret_item_new_for_dbus_path_finish (result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); g_clear_object (&task); return; } if (item != NULL) { path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)); g_hash_table_insert (closure->items, g_strdup (path), item); } if (closure->items_loading == 0) { collection_update_items (self, closure->items); g_task_return_boolean (task, TRUE); } g_clear_object (&task); } /** * secret_collection_load_items: * @self: the secret collection * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Ensure that the #SecretCollection proxy has loaded all the items present * in the Secret Service. * * This affects the result of [method@Collection.get_items]. * * For collections returned from [method@Service.get_collections] the items will * have already been loaded. * * This method will return immediately and complete asynchronously. */ void secret_collection_load_items (SecretCollection *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { ItemsClosure *closure; SecretItem *item; GTask *task; const gchar *path; GVariant *paths; GVariantIter iter; g_return_if_fail (SECRET_IS_COLLECTION (self)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items"); g_return_if_fail (paths != NULL); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_collection_load_items); closure = g_new0 (ItemsClosure, 1); closure->items = items_table_new (); g_task_set_task_data (task, closure, items_closure_free); g_variant_iter_init (&iter, paths); while (g_variant_iter_loop (&iter, "&o", &path)) { item = _secret_collection_find_item_instance (self, path); /* No such collection yet create a new one */ if (item == NULL) { secret_item_new_for_dbus_path (self->pv->service, path, SECRET_ITEM_NONE, cancellable, on_load_item, g_object_ref (task)); closure->items_loading++; } else { g_hash_table_insert (closure->items, g_strdup (path), item); } } if (closure->items_loading == 0) { collection_update_items (self, closure->items); g_task_return_boolean (task, TRUE); } g_variant_unref (paths); g_clear_object (&task); } /** * secret_collection_load_items_finish: * @self: the secret collection * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Complete an asynchronous operation to ensure that the #SecretCollection proxy * has loaded all the items present in the Secret Service. * * Returns: whether the load was successful or not */ gboolean secret_collection_load_items_finish (SecretCollection *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_task_is_valid (result, self), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_collection_load_items_sync: * @self: the secret collection * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Ensure that the #SecretCollection proxy has loaded all the items present * in the Secret Service. This affects the result of * [method@Collection.get_items]. * * For collections returned from [method@Service.get_collections] the items * will have already been loaded. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the load was successful or not */ gboolean secret_collection_load_items_sync (SecretCollection *self, GCancellable *cancellable, GError **error) { SecretItem *item; GHashTable *items; GVariant *paths; GVariantIter iter; const gchar *path; gboolean ret = TRUE; g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items"); g_return_val_if_fail (paths != NULL, FALSE); items = items_table_new (); g_variant_iter_init (&iter, paths); while (g_variant_iter_next (&iter, "&o", &path)) { item = _secret_collection_find_item_instance (self, path); /* No such collection yet create a new one */ if (item == NULL) { item = secret_item_new_for_dbus_path_sync (self->pv->service, path, SECRET_ITEM_NONE, cancellable, error); if (item == NULL) { ret = FALSE; break; } } g_hash_table_insert (items, g_strdup (path), item); } if (ret) collection_update_items (self, items); g_hash_table_unref (items); g_variant_unref (paths); return ret; } /** * secret_collection_refresh: * @self: the collection * * Refresh the properties on this collection. This fires off a request to * refresh, and the properties will be updated later. * * Calling this method is not normally necessary, as the secret service * will notify the client when properties change. */ void secret_collection_refresh (SecretCollection *self) { g_return_if_fail (SECRET_IS_COLLECTION (self)); _secret_util_get_properties (G_DBUS_PROXY (self), secret_collection_refresh, self->pv->cancellable, NULL, NULL); } typedef struct { SecretCollection *collection; GHashTable *properties; gchar *alias; SecretCollectionCreateFlags flags; } CreateClosure; static void create_closure_free (gpointer data) { CreateClosure *closure = data; g_clear_object (&closure->collection); g_hash_table_unref (closure->properties); g_free (closure->alias); g_free (closure); } static void on_create_collection (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretCollection *collection; GError *error = NULL; collection = secret_collection_new_for_dbus_path_finish (result, &error); if (error != NULL) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_pointer (task, collection, g_object_unref); g_clear_object (&task); } static void on_create_path (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GCancellable *cancellable = g_task_get_cancellable (task); SecretService *service = SECRET_SERVICE (source); GError *error = NULL; gchar *path; path = secret_service_create_collection_dbus_path_finish (service, result, &error); if (error == NULL) { secret_collection_new_for_dbus_path (service, path, SECRET_COLLECTION_LOAD_ITEMS, cancellable, on_create_collection, g_steal_pointer (&task)); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_free (path); g_clear_object (&task); } static void on_create_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); CreateClosure *create = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; SecretService *service; service = secret_service_get_finish (result, &error); if (error == NULL) { secret_service_create_collection_dbus_path (service, create->properties, create->alias, create->flags, cancellable, on_create_path, g_steal_pointer (&task)); g_object_unref (service); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } GHashTable * _secret_collection_properties_new (const gchar *label) { GHashTable *properties; GVariant *value; properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_variant_unref); value = g_variant_new_string (label); g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", g_variant_ref_sink (value)); return properties; } /** * secret_collection_create: * @service: (nullable): a secret service object * @label: label for the new collection * @alias: (nullable): alias to assign to the collection * @flags: currently unused * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Create a new collection in the secret service. * * This method returns immediately and completes asynchronously. The secret * service may prompt the user. [method@Service.prompt] will be used to handle * any prompts that are required. * * An @alias is a well-known tag for a collection, such as 'default' (ie: the * default collection to store items in). This allows other applications to * easily identify and share a collection. If you specify an @alias, and a * collection with that alias already exists, then a new collection will not * be created. The previous one will be returned instead. * * If @service is %NULL, then [func@Service.get] will be called to get the * default [class@Service] proxy. */ void secret_collection_create (SecretService *service, const gchar *label, const gchar *alias, SecretCollectionCreateFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; CreateClosure *closure; g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (label != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (NULL, cancellable, callback, user_data); g_task_set_source_tag (task, secret_collection_create); closure = g_new0 (CreateClosure, 1); closure->properties = _secret_collection_properties_new (label); closure->alias = g_strdup (alias); closure->flags = flags; g_task_set_task_data (task, closure, create_closure_free); if (service == NULL) { secret_service_get (SECRET_SERVICE_NONE, cancellable, on_create_service, g_steal_pointer (&task)); } else { secret_service_create_collection_dbus_path (service, closure->properties, closure->alias, closure->flags, cancellable, on_create_path, g_steal_pointer (&task)); } g_clear_object (&task); } /** * secret_collection_create_finish: * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish operation to create a new collection in the secret service. * * Returns: (transfer full): the new collection, which should be unreferenced * with [method@GObject.Object.unref] */ SecretCollection * secret_collection_create_finish (GAsyncResult *result, GError **error) { SecretCollection *collection; g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); collection = g_task_propagate_pointer (G_TASK (result), error); if (!collection) { _secret_util_strip_remote_error (error); return NULL; } return collection; } /** * secret_collection_create_sync: * @service: (nullable): a secret service object * @label: label for the new collection * @alias: (nullable): alias to assign to the collection * @flags: currently unused * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Create a new collection in the secret service. * * This method may block indefinitely and should not be used in user interface * threads. The secret service may prompt the user. [method@Service.prompt] * will be used to handle any prompts that are required. * * An @alias is a well-known tag for a collection, such as `default` (ie: the * default collection to store items in). This allows other applications to * easily identify and share a collection. If you specify an @alias, and a * collection with that alias already exists, then a new collection will not * be created. The previous one will be returned instead. * * If @service is %NULL, then [func@Service.get_sync] will be called to get the * default [class@Service] proxy. * * Returns: (transfer full): the new collection, which should be unreferenced * with [method@GObject.Object.unref] */ SecretCollection * secret_collection_create_sync (SecretService *service, const gchar *label, const gchar *alias, SecretCollectionCreateFlags flags, GCancellable *cancellable, GError **error) { SecretCollection *collection; GHashTable *properties; gchar *path; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (label != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); if (service == NULL) { service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error); if (service == NULL) return NULL; } else { g_object_ref (service); } properties = _secret_collection_properties_new (label); path = secret_service_create_collection_dbus_path_sync (service, properties, alias, flags, cancellable, error); g_hash_table_unref (properties); if (path == NULL) { g_object_unref (service); return NULL; } collection = secret_collection_new_for_dbus_path_sync (service, path, SECRET_COLLECTION_LOAD_ITEMS, cancellable, error); g_object_unref (service); g_free (path); return collection; } typedef struct { SecretCollection *collection; GHashTable *items; gchar **paths; guint loading; SecretSearchFlags flags; } SearchClosure; static void search_closure_free (gpointer data) { SearchClosure *closure = data; g_object_unref (closure->collection); g_hash_table_unref (closure->items); g_strfreev (closure->paths); g_free (closure); } static void search_closure_take_item (SearchClosure *closure, SecretItem *item) { const gchar *path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)); g_hash_table_insert (closure->items, (gpointer)path, item); } static void on_search_secrets (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); /* Note that we ignore any unlock failure */ secret_item_load_secrets_finish (result, NULL); g_task_return_boolean (task, TRUE); g_clear_object (&task); } static void on_search_unlocked (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SearchClosure *search = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GList *items; /* Note that we ignore any unlock failure */ secret_service_unlock_finish (SECRET_SERVICE (source), result, NULL, NULL); /* If loading secrets ... locked items automatically ignored */ if (search->flags & SECRET_SEARCH_LOAD_SECRETS) { items = g_hash_table_get_values (search->items); secret_item_load_secrets (items, cancellable, on_search_secrets, g_object_ref (task)); g_list_free (items); /* No additional options, just complete */ } else { g_task_return_boolean (task, TRUE); } g_clear_object (&task); } static void secret_search_unlock_load_or_complete (GTask *task, SearchClosure *search) { GList *items; GCancellable *cancellable = g_task_get_cancellable (task); /* If unlocking then unlock all the locked items */ if (search->flags & SECRET_SEARCH_UNLOCK) { items = g_hash_table_get_values (search->items); secret_service_unlock (secret_collection_get_service (search->collection), items, cancellable, on_search_unlocked, g_object_ref (task)); g_list_free (items); /* If loading secrets ... locked items automatically ignored */ } else if (search->flags & SECRET_SEARCH_LOAD_SECRETS) { items = g_hash_table_get_values (search->items); secret_item_load_secrets (items, cancellable, on_search_secrets, g_object_ref (task)); g_list_free (items); /* No additional options, just complete */ } else { g_task_return_boolean (task, TRUE); } } static void on_search_loaded (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SearchClosure *search = g_task_get_task_data (task); GError *error = NULL; SecretItem *item; search->loading--; item = secret_item_new_for_dbus_path_finish (result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); g_clear_object (&task); return; } if (item != NULL) search_closure_take_item (search, item); /* We're done loading, lets go to the next step */ if (search->loading == 0) secret_search_unlock_load_or_complete (task, search); g_clear_object (&task); } static void on_search_paths (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SearchClosure *search = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); SecretCollection *self = search->collection; SecretService *service = secret_collection_get_service (self); GError *error = NULL; SecretItem *item; gint want = 1; gint i; search->paths = secret_collection_search_for_dbus_paths_finish (self, result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); g_clear_object (&task); return; } want = 1; if (search->flags & SECRET_SEARCH_ALL) want = G_MAXINT; for (i = 0; i < want && search->paths[i] != NULL; i++) { item = _secret_collection_find_item_instance (self, search->paths[i]); if (item == NULL) { secret_item_new_for_dbus_path (service, search->paths[i], SECRET_ITEM_NONE, cancellable, on_search_loaded, g_object_ref (task)); search->loading++; } else { search_closure_take_item (search, item); } } /* No items loading, complete operation now */ if (search->loading == 0) secret_search_unlock_load_or_complete (task, search); g_clear_object (&task); } /** * secret_collection_search: * @self: a secret collection * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @flags: search option flags * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Search for items matching the @attributes in the @collection. * The @attributes should be a table of string keys and string values. * * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the * search will be returned. Otherwise only the first item will be returned. * This is almost always the unlocked item that was most recently stored. * * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked * if necessary. In either case, locked and unlocked items will match the * search and be returned. If the unlock fails, the search does not fail. * * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items will have * their secret values loaded and available via [method@Item.get_secret]. * * This function returns immediately and completes asynchronously. */ void secret_collection_search (SecretCollection *self, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; SearchClosure *search; g_return_if_fail (SECRET_IS_COLLECTION (self)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_collection_search); search = g_new0 (SearchClosure, 1); search->collection = g_object_ref (self); search->items = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); search->flags = flags; g_task_set_task_data (task, search, search_closure_free); secret_collection_search_for_dbus_paths (self, schema, attributes, cancellable, on_search_paths, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_collection_search_finish: * @self: the secret collection * @result: asynchronous result passed to callback * @error: location to place error on failure * * Complete asynchronous operation to search for items in a collection. * * Returns: (transfer full) (element-type Secret.Item): * a list of items that matched the search */ GList * secret_collection_search_finish (SecretCollection *self, GAsyncResult *result, GError **error) { SearchClosure *search; GList *items = NULL; SecretItem *item; guint i; g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (g_task_is_valid (result, self), NULL); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return NULL; } search = g_task_get_task_data (G_TASK (result)); for (i = 0; search->paths[i]; i++) { item = g_hash_table_lookup (search->items, search->paths[i]); if (item != NULL) items = g_list_prepend (items, g_object_ref (item)); } return g_list_reverse (items); } static gboolean collection_load_items_sync (SecretCollection *self, GCancellable *cancellable, gchar **paths, GList **items, gint want, GError **error) { SecretService *service = secret_collection_get_service (self); SecretItem *item; gint have = 0; guint i; for (i = 0; have < want && paths[i] != NULL; i++) { item = _secret_collection_find_item_instance (self, paths[i]); if (item == NULL) item = secret_item_new_for_dbus_path_sync (service, paths[i], SECRET_ITEM_NONE, cancellable, error); if (item == NULL) { return FALSE; } else { *items = g_list_prepend (*items, item); have++; } } return TRUE; } /** * secret_collection_search_sync: * @self: a secret collection * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @flags: search option flags * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Search for items matching the @attributes in the @collection. * The @attributes should be a table of string keys and string values. * * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the * search will be returned. Otherwise only the first item will be returned. * This is almost always the unlocked item that was most recently stored. * * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked * if necessary. In either case, locked and unlocked items will match the * search and be returned. If the unlock fails, the search does not fail. * * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items will have * their secret values loaded and available via [method@Item.get_secret]. * * This function may block indefinitely. Use the asynchronous version * in user interface threads. * * Returns: (transfer full) (element-type Secret.Item): * a list of items that matched the search */ GList * secret_collection_search_sync (SecretCollection *self, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GError **error) { gchar **paths = NULL; GList *items = NULL; gboolean ret; gint want; g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return NULL; paths = secret_collection_search_for_dbus_paths_sync (self, schema, attributes, cancellable, error); if (paths == NULL) return NULL; want = 1; if (flags & SECRET_SEARCH_ALL) want = G_MAXINT; ret = collection_load_items_sync (self, cancellable, paths, &items, want, error); g_strfreev (paths); if (!ret) return NULL; if (flags & SECRET_SEARCH_UNLOCK) { secret_service_unlock_sync (secret_collection_get_service (self), items, cancellable, NULL, NULL); } if (flags & SECRET_SEARCH_LOAD_SECRETS) secret_item_load_secrets_sync (items, NULL, NULL); return items; } static void on_service_delete_path (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GError *error = NULL; _secret_service_delete_path_finish (SECRET_SERVICE (source), result, &error); if (error != NULL) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_boolean (task, TRUE); g_clear_object (&task); } /** * secret_collection_delete: * @self: a collection * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Delete this collection. * * This method returns immediately and completes asynchronously. The secret * service may prompt the user. [method@Service.prompt] will be used to handle * any prompts that show up. */ void secret_collection_delete (SecretCollection *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; const gchar *object_path; g_return_if_fail (SECRET_IS_COLLECTION (self)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_collection_delete); object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self)); _secret_service_delete_path (self->pv->service, object_path, FALSE, cancellable, on_service_delete_path, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_collection_delete_finish: * @self: a collection * @result: asynchronous result passed to the callback * @error: location to place an error on failure * * Complete operation to delete this collection. * * Returns: whether the collection was successfully deleted or not */ gboolean secret_collection_delete_finish (SecretCollection *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_task_is_valid (result, self), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_collection_delete_sync: * @self: a collection * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Delete this collection. * * This method may block indefinitely and should not be used in user interface * threads. The secret service may prompt the user. [method@Service.prompt] will * be used to handle any prompts that show up. * * Returns: whether the collection was successfully deleted or not */ gboolean secret_collection_delete_sync (SecretCollection *self, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_collection_delete (self, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_collection_delete_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } /** * secret_collection_get_service: (attributes org.gtk.Method.get_property=service) * @self: a collection * * Get the Secret Service object that this collection was created with. * * Returns: (transfer none): the Secret Service object */ SecretService * secret_collection_get_service (SecretCollection *self) { g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL); return self->pv->service; } /** * secret_collection_get_flags: (attributes org.gtk.Method.get_property=flags) * @self: the secret collection proxy * * Get the flags representing what features of the #SecretCollection proxy * have been initialized. * * Use [method@Collection.load_items] to initialize further features and change * the flags. * * Returns: the flags for features initialized */ SecretCollectionFlags secret_collection_get_flags (SecretCollection *self) { SecretCollectionFlags flags = 0; g_return_val_if_fail (SECRET_IS_COLLECTION (self), SECRET_COLLECTION_NONE); g_mutex_lock (&self->pv->mutex); if (self->pv->items) flags |= SECRET_COLLECTION_LOAD_ITEMS; g_mutex_unlock (&self->pv->mutex); return flags; } /** * secret_collection_get_items: (attributes org.gtk.Method.get_property=items) * @self: a collection * * Get the list of items in this collection. * * Returns: (transfer full) (element-type Secret.Item): a list of items, when * done, the list should be freed with [func@GLib.List.free], and each item * should be released with [method@GObject.Object.unref] */ GList * secret_collection_get_items (SecretCollection *self) { GList *l, *items = NULL; g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL); g_mutex_lock (&self->pv->mutex); if (self->pv->items) items = g_hash_table_get_values (self->pv->items); for (l = items; l != NULL; l = g_list_next (l)) g_object_ref (l->data); g_mutex_unlock (&self->pv->mutex); return items; } SecretItem * _secret_collection_find_item_instance (SecretCollection *self, const gchar *item_path) { SecretItem *item = NULL; g_mutex_lock (&self->pv->mutex); if (self->pv->items) item = g_hash_table_lookup (self->pv->items, item_path); if (item != NULL) g_object_ref (item); g_mutex_unlock (&self->pv->mutex); return item; } /** * secret_collection_get_label: (attributes org.gtk.Method.get_property=label) * @self: a collection * * Get the label of this collection. * * Returns: (transfer full): the label, which should be freed with * [func@GLib.free] */ gchar * secret_collection_get_label (SecretCollection *self) { GVariant *variant; gchar *label; g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Label"); g_return_val_if_fail (variant != NULL, NULL); label = g_variant_dup_string (variant, NULL); g_variant_unref (variant); return label; } /** * secret_collection_set_label: (attributes org.gtk.Method.set_property=label) * @self: a collection * @label: a new label * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Set the label of this collection. * * This function returns immediately and completes asynchronously. */ void secret_collection_set_label (SecretCollection *self, const gchar *label, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_COLLECTION (self)); g_return_if_fail (label != NULL); _secret_util_set_property (G_DBUS_PROXY (self), "Label", g_variant_new_string (label), secret_collection_set_label, cancellable, callback, user_data); } /** * secret_collection_set_label_finish: * @self: a collection * @result: asynchronous result passed to callback * @error: location to place error on failure * * Complete asynchronous operation to set the label of this collection. * * Returns: whether the change was successful or not */ gboolean secret_collection_set_label_finish (SecretCollection *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE); return _secret_util_set_property_finish (G_DBUS_PROXY (self), secret_collection_set_label, result, error); } /** * secret_collection_set_label_sync: * @self: a collection * @label: a new label * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Set the label of this collection. * * This function may block indefinitely. Use the asynchronous version * in user interface threads. * * Returns: whether the change was successful or not */ gboolean secret_collection_set_label_sync (SecretCollection *self, const gchar *label, GCancellable *cancellable, GError **error) { g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE); g_return_val_if_fail (label != NULL, FALSE); return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Label", g_variant_new_string (label), cancellable, error); } /** * secret_collection_get_locked: (attributes org.gtk.Method.get_property=locked) * @self: a collection * * Get whether the collection is locked or not. * * Use [method@Service.lock] or [method@Service.unlock] to lock or unlock the * collection. * * Returns: whether the collection is locked or not */ gboolean secret_collection_get_locked (SecretCollection *self) { GVariant *variant; gboolean locked; g_return_val_if_fail (SECRET_IS_COLLECTION (self), TRUE); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Locked"); g_return_val_if_fail (variant != NULL, TRUE); locked = g_variant_get_boolean (variant); g_variant_unref (variant); return locked; } /** * secret_collection_get_created: (attributes org.gtk.Method.get_property=created) * @self: a collection * * Get the created date and time of the collection. * * The return value is the number of seconds since the unix epoch, January 1st * 1970. * * Returns: the created date and time */ guint64 secret_collection_get_created (SecretCollection *self) { GVariant *variant; guint64 created; g_return_val_if_fail (SECRET_IS_COLLECTION (self), TRUE); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Created"); g_return_val_if_fail (variant != NULL, 0); created = g_variant_get_uint64 (variant); g_variant_unref (variant); return created; } /** * secret_collection_get_modified: (attributes org.gtk.Method.get_property=modified) * @self: a collection * * Get the modified date and time of the collection. * * The return value is the number of seconds since the unix epoch, January 1st * 1970. * * Returns: the modified date and time */ guint64 secret_collection_get_modified (SecretCollection *self) { GVariant *variant; guint64 modified; g_return_val_if_fail (SECRET_IS_COLLECTION (self), TRUE); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Modified"); g_return_val_if_fail (variant != NULL, 0); modified = g_variant_get_uint64 (variant); g_variant_unref (variant); return modified; } typedef struct { gchar *alias; SecretCollectionFlags flags; } ReadClosure; static void read_closure_free (gpointer data) { ReadClosure *read = data; g_free (read->alias); g_free (read); } static void on_read_alias_collection (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretCollection *collection; GError *error = NULL; collection = secret_collection_new_for_dbus_path_finish (result, &error); if (error != NULL) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_pointer (task, collection, g_object_unref); g_clear_object (&task); } static void on_read_alias_path (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); ReadClosure *read = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); SecretService *self = SECRET_SERVICE (source); GError *error = NULL; gchar *collection_path; collection_path = secret_service_read_alias_dbus_path_finish (self, result, &error); if (error == NULL) { /* No collection for this alias */ if (collection_path == NULL) { g_task_return_pointer (task, NULL, NULL); } else { SecretCollection *collection; collection = _secret_service_find_collection_instance (self, collection_path); if (collection != NULL) { /* Make sure collection has necessary flags */ collection_ensure_for_flags_async (collection, read->flags, task); /* No collection loaded, but valid path, load */ } else { secret_collection_new_for_dbus_path (self, collection_path, read->flags, cancellable, on_read_alias_collection, g_steal_pointer (&task)); } } } else { g_task_return_error (task, g_steal_pointer (&error)); } g_free (collection_path); g_clear_object (&task); } static void on_read_alias_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); ReadClosure *read = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); SecretService *service; GError *error = NULL; service = secret_service_get_finish (result, &error); if (error == NULL) { secret_service_read_alias_dbus_path (service, read->alias, cancellable, on_read_alias_path, g_steal_pointer (&task)); g_object_unref (service); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } /** * secret_collection_for_alias: * @service: (nullable): a secret service object * @alias: the alias to lookup * @flags: options for the collection initialization * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Lookup which collection is assigned to this alias. Aliases help determine * well known collections, such as 'default'. * * If @service is %NULL, then [func@Service.get] will be called to get the * default [class@Service] proxy. * * This method will return immediately and complete asynchronously. */ void secret_collection_for_alias (SecretService *service, const gchar *alias, SecretCollectionFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; ReadClosure *read; g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (alias != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (NULL, cancellable, callback, user_data); g_task_set_source_tag (task, secret_collection_for_alias); read = g_new0 (ReadClosure, 1); read->alias = g_strdup (alias); read->flags = flags; g_task_set_task_data (task, read, read_closure_free); if (service == NULL) { secret_service_get (SECRET_SERVICE_NONE, cancellable, on_read_alias_service, g_object_ref (task)); } else { secret_service_read_alias_dbus_path (service, read->alias, cancellable, on_read_alias_path, g_steal_pointer (&task)); } g_clear_object (&task); } /** * secret_collection_for_alias_finish: * @result: asynchronous result passed to callback * @error: location to place error on failure * * Finish an asynchronous operation to lookup which collection is assigned * to an alias. * * Returns: (transfer full) (nullable): the collection, or %NULL if none assigned to the alias */ SecretCollection * secret_collection_for_alias_finish (GAsyncResult *result, GError **error) { SecretCollection *collection; g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); collection = g_task_propagate_pointer (G_TASK (result), error); if (error && *error) { _secret_util_strip_remote_error (error); return NULL; } return collection; } /** * secret_collection_for_alias_sync: * @service: (nullable): a secret service object * @alias: the alias to lookup * @flags: options for the collection initialization * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Lookup which collection is assigned to this alias. Aliases help determine * well known collections, such as `default`. * * If @service is %NULL, then [func@Service.get_sync] will be called to get the * default [class@Service] proxy. * * This method may block and should not be used in user interface threads. * * Returns: (transfer full) (nullable): the collection, or %NULL if none assigned to the alias */ SecretCollection * secret_collection_for_alias_sync (SecretService *service, const gchar *alias, SecretCollectionFlags flags, GCancellable *cancellable, GError **error) { SecretCollection *collection; gchar *collection_path; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (alias != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); collection_path = secret_service_read_alias_dbus_path_sync (service, alias, cancellable, error); /* No collection for this alias */ if (collection_path == NULL) return NULL; collection = _secret_service_find_collection_instance (service, collection_path); if (collection != NULL) { /* Have a collection with all necessary flags */ if (!collection_ensure_for_flags_sync (collection, flags, cancellable, error)) { g_object_unref (collection); collection = NULL; } /* No collection loaded, but valid path, load */ } else { collection = secret_collection_new_for_dbus_path_sync (service, collection_path, flags, cancellable, error); } g_free (collection_path); return collection; } 0707010000005E000081A400000000000000000000000167D9F0D9000025DA000000000000000000000000000000000000002F00000000libsecret-0.21.7/libsecret/secret-collection.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_COLLECTION_H__ #define __SECRET_COLLECTION_H__ #include #include "secret-schema.h" #include "secret-service.h" #include "secret-types.h" G_BEGIN_DECLS typedef enum { /*< prefix=SECRET_COLLECTION >*/ SECRET_COLLECTION_NONE = 0 << 0, SECRET_COLLECTION_LOAD_ITEMS = 1 << 1, } SecretCollectionFlags; typedef enum { /*< prefix=SECRET_COLLECTION_CREATE >*/ SECRET_COLLECTION_CREATE_NONE = 0 << 0, } SecretCollectionCreateFlags; #define SECRET_TYPE_COLLECTION (secret_collection_get_type ()) #define SECRET_COLLECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), SECRET_TYPE_COLLECTION, SecretCollection)) #define SECRET_COLLECTION_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), SECRET_TYPE_COLLECTION, SecretCollectionClass)) #define SECRET_IS_COLLECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), SECRET_TYPE_COLLECTION)) #define SECRET_IS_COLLECTION_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), SECRET_TYPE_COLLECTION)) #define SECRET_COLLECTION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), SECRET_TYPE_COLLECTION, SecretCollectionClass)) typedef struct _SecretItem SecretItem; typedef struct _SecretCollectionClass SecretCollectionClass; typedef struct _SecretCollectionPrivate SecretCollectionPrivate; struct _SecretCollection { GDBusProxy parent; /*< private >*/ SecretCollectionPrivate *pv; }; struct _SecretCollectionClass { GDBusProxyClass parent_class; /*< private >*/ gpointer padding[8]; }; GType secret_collection_get_type (void) G_GNUC_CONST; void secret_collection_for_alias (SecretService *service, const gchar *alias, SecretCollectionFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretCollection * secret_collection_for_alias_finish (GAsyncResult *result, GError **error); SecretCollection * secret_collection_for_alias_sync (SecretService *service, const gchar *alias, SecretCollectionFlags flags, GCancellable *cancellable, GError **error); void secret_collection_load_items (SecretCollection *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_collection_load_items_finish (SecretCollection *self, GAsyncResult *result, GError **error); gboolean secret_collection_load_items_sync (SecretCollection *self, GCancellable *cancellable, GError **error); void secret_collection_refresh (SecretCollection *self); void secret_collection_create (SecretService *service, const gchar *label, const gchar *alias, SecretCollectionCreateFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretCollection * secret_collection_create_finish (GAsyncResult *result, GError **error); SecretCollection * secret_collection_create_sync (SecretService *service, const gchar *label, const gchar *alias, SecretCollectionCreateFlags flags, GCancellable *cancellable, GError **error); void secret_collection_search (SecretCollection *self, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GList * secret_collection_search_finish (SecretCollection *self, GAsyncResult *result, GError **error); GList * secret_collection_search_sync (SecretCollection *self, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GError **error); void secret_collection_delete (SecretCollection *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_collection_delete_finish (SecretCollection *self, GAsyncResult *result, GError **error); gboolean secret_collection_delete_sync (SecretCollection *self, GCancellable *cancellable, GError **error); SecretService * secret_collection_get_service (SecretCollection *self); SecretCollectionFlags secret_collection_get_flags (SecretCollection *self); GList * secret_collection_get_items (SecretCollection *self); gchar * secret_collection_get_label (SecretCollection *self); void secret_collection_set_label (SecretCollection *self, const gchar *label, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_collection_set_label_finish (SecretCollection *self, GAsyncResult *result, GError **error); gboolean secret_collection_set_label_sync (SecretCollection *self, const gchar *label, GCancellable *cancellable, GError **error); gboolean secret_collection_get_locked (SecretCollection *self); guint64 secret_collection_get_created (SecretCollection *self); guint64 secret_collection_get_modified (SecretCollection *self); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecretCollection, g_object_unref) G_END_DECLS #endif /* __SECRET_COLLECTION_H___ */ 0707010000005F000081A400000000000000000000000167D9F0D90000054F000000000000000000000000000000000000003800000000libsecret-0.21.7/libsecret/secret-enum-types.c.template/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ /*** BEGIN file-header ***/ #include #ifndef SECRET_COMPILATION #define SECRET_COMPILATION #endif /*** END file-header ***/ /*** BEGIN file-production ***/ #include "@basename@" /* enumerations from "@basename@" */ /*** END file-production ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type (void) G_GNUC_CONST; GType @enum_name@_get_type (void) { static GType etype = 0; if (G_UNLIKELY(etype == 0)) { static const G@Type@Value values[] = { /*** END value-header ***/ /*** BEGIN value-production ***/ { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, /*** END value-production ***/ /*** BEGIN value-tail ***/ { 0, NULL, NULL } }; etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); } return etype; } /*** END value-tail ***/ /*** BEGIN file-tail ***/ /**/ /*** END file-tail ***/ 07070100000060000081A400000000000000000000000167D9F0D900000460000000000000000000000000000000000000003800000000libsecret-0.21.7/libsecret/secret-enum-types.h.template/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ /*** BEGIN file-header ***/ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_ENUM_TYPES_H__ #define __SECRET_ENUM_TYPES_H__ #include G_BEGIN_DECLS /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@basename@" */ /*** END file-production ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type (void) G_GNUC_CONST; #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) /*** END value-header ***/ /*** BEGIN file-tail ***/ G_END_DECLS #endif /* __SECRET_ENUM_TYPES_H__ */ /*** END file-tail ***/ 07070100000061000081A400000000000000000000000167D9F0D900006305000000000000000000000000000000000000003100000000libsecret-0.21.7/libsecret/secret-file-backend.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #include "config.h" #include "secret-backend.h" #include "secret-file-backend.h" #include "secret-file-collection.h" #include "secret-file-item.h" #include "secret-private.h" #include "secret-retrievable.h" #include "egg/egg-secure-memory.h" #include "egg/egg-tpm2.h" EGG_SECURE_DECLARE (secret_file_backend); #include #include #include #define PORTAL_BUS_NAME "org.freedesktop.portal.Desktop" #define PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop" #define PORTAL_REQUEST_INTERFACE "org.freedesktop.portal.Request" #define PORTAL_REQUEST_PATH_PREFIX "/org/freedesktop/portal/desktop/request/" #define PORTAL_SECRET_INTERFACE "org.freedesktop.portal.Secret" #define PORTAL_SECRET_VERSION 1 static void secret_file_backend_async_initable_iface (GAsyncInitableIface *iface); static void secret_file_backend_backend_iface (SecretBackendInterface *iface); struct _SecretFileBackend { GObject parent; SecretFileCollection *collection; SecretServiceFlags init_flags; }; G_DEFINE_TYPE_WITH_CODE (SecretFileBackend, secret_file_backend, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_file_backend_async_initable_iface); G_IMPLEMENT_INTERFACE (SECRET_TYPE_BACKEND, secret_file_backend_backend_iface); _secret_backend_ensure_extension_point (); g_io_extension_point_implement (SECRET_BACKEND_EXTENSION_POINT_NAME, g_define_type_id, "file", 0) ); enum { PROP_0, PROP_FLAGS }; /* Gets the GFile for this backend and makes sure the parent dirs exist */ static GFile * get_secret_file (GCancellable *cancellable, GError **error) { const char *envvar = NULL; char *path = NULL; GFile *file = NULL; GFile *dir = NULL; gboolean ret; envvar = g_getenv ("SECRET_FILE_TEST_PATH"); if (envvar != NULL && *envvar != '\0') { path = g_strdup (envvar); } else { path = g_build_filename (g_get_user_data_dir (), "keyrings", SECRET_COLLECTION_DEFAULT ".keyring", NULL); } file = g_file_new_for_path (path); g_free (path); dir = g_file_get_parent (file); if (dir == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "not a valid path"); g_object_unref (file); return NULL; } ret = g_file_make_directory_with_parents (dir, cancellable, error); g_object_unref (dir); if (!ret) { if (!g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { g_object_unref (file); return NULL; } g_clear_error (error); } return file; } static void secret_file_backend_init (SecretFileBackend *self) { } static void secret_file_backend_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { SecretFileBackend *self = SECRET_FILE_BACKEND (object); switch (prop_id) { case PROP_FLAGS: self->init_flags = g_value_get_flags (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void secret_file_backend_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { SecretFileBackend *self = SECRET_FILE_BACKEND (object); switch (prop_id) { case PROP_FLAGS: g_value_set_flags (value, self->init_flags); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void secret_file_backend_finalize (GObject *object) { SecretFileBackend *self = SECRET_FILE_BACKEND (object); g_clear_object (&self->collection); G_OBJECT_CLASS (secret_file_backend_parent_class)->finalize (object); } static void secret_file_backend_class_init (SecretFileBackendClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = secret_file_backend_set_property; object_class->get_property = secret_file_backend_get_property; object_class->finalize = secret_file_backend_finalize; /** * SecretFileBackend:flags: * * A set of flags describing which parts of the secret file have * been initialized. */ g_object_class_override_property (object_class, PROP_FLAGS, "flags"); } static void on_collection_new_async (GObject *source_object, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretFileBackend *self = g_task_get_source_object (task); GObject *object; GError *error = NULL; object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, &error); if (object == NULL) { g_task_return_error (task, error); g_object_unref (task); return; } self->collection = SECRET_FILE_COLLECTION (object); g_task_return_boolean (task, TRUE); g_object_unref (task); } typedef struct { gint io_priority; GFile *file; GInputStream *stream; gchar *buffer; GDBusConnection *connection; gchar *request_path; guint portal_signal_id; GCancellable *cancellable; gulong cancellable_signal_id; gchar *sender; } InitClosure; static void init_closure_free (gpointer data) { InitClosure *init = data; g_object_unref (init->file); g_clear_object (&init->stream); g_clear_pointer (&init->buffer, egg_secure_free); g_clear_object (&init->connection); g_clear_pointer (&init->request_path, g_free); g_clear_pointer (&init->sender, g_free); if (init->cancellable_signal_id) { g_cancellable_disconnect (init->cancellable, init->cancellable_signal_id); init->cancellable_signal_id = 0; } /* Note: do not cancel the cancellable here! That's for the API user to * do. We're just keeping track of it here so we can disconnect. */ g_clear_object (&init->cancellable); g_free (init); } #define PASSWORD_SIZE 64 static void on_read_all (GObject *source_object, GAsyncResult *result, gpointer user_data) { GInputStream *stream = G_INPUT_STREAM (source_object); GTask *task = G_TASK (user_data); InitClosure *init = g_task_get_task_data (task); gsize bytes_read; SecretValue *password; GError *error = NULL; if (!g_input_stream_read_all_finish (stream, result, &bytes_read, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } if (bytes_read != PASSWORD_SIZE) { g_task_return_new_error (task, SECRET_ERROR, SECRET_ERROR_PROTOCOL, "invalid password returned from portal"); g_object_unref (task); return; } password = secret_value_new (init->buffer, bytes_read, "text/plain"); g_async_initable_new_async (SECRET_TYPE_FILE_COLLECTION, init->io_priority, g_task_get_cancellable (task), on_collection_new_async, task, "file", g_object_ref (init->file), "password", password, NULL); g_object_unref (init->file); secret_value_unref (password); } static void on_portal_response (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { GTask *task = G_TASK (user_data); InitClosure *init = g_task_get_task_data (task); guint32 response; if (init->cancellable_signal_id) { g_cancellable_disconnect (g_task_get_cancellable (task), init->cancellable_signal_id); init->cancellable_signal_id = 0; } g_dbus_connection_signal_unsubscribe (connection, init->portal_signal_id); g_variant_get (parameters, "(ua{sv})", &response, NULL); switch (response) { case 0: init->buffer = egg_secure_alloc (PASSWORD_SIZE); g_input_stream_read_all_async (init->stream, init->buffer, PASSWORD_SIZE, G_PRIORITY_DEFAULT, g_task_get_cancellable (task), on_read_all, task); break; case 1: g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "user interaction cancelled"); g_object_unref (task); break; case 2: g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "user interaction failed"); g_object_unref (task); break; } } static void on_portal_request_close (GObject *source_object, GAsyncResult *result, gpointer user_data) { GDBusConnection *connection = G_DBUS_CONNECTION (source_object); GTask *task = G_TASK (user_data); GError *error = NULL; if (!g_dbus_connection_call_finish (connection, result, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } g_task_return_boolean (task, TRUE); g_object_unref (task); } static void on_portal_cancel (GCancellable *cancellable, gpointer user_data) { GTask *task = G_TASK (user_data); InitClosure *init = g_task_get_task_data (task); g_dbus_connection_call (init->connection, PORTAL_BUS_NAME, init->request_path, PORTAL_REQUEST_INTERFACE, "Close", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_portal_request_close, task); } static void on_portal_retrieve_secret (GObject *source_object, GAsyncResult *result, gpointer user_data) { GDBusConnection *connection = G_DBUS_CONNECTION (source_object); GTask *task = G_TASK (user_data); InitClosure *init = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GVariant *reply; GError *error = NULL; reply = g_dbus_connection_call_with_unix_fd_list_finish (connection, NULL, result, &error); if (reply == NULL) { g_task_return_error (task, error); g_object_unref (task); return; } g_variant_unref (reply); if (cancellable != NULL) init->cancellable_signal_id = g_cancellable_connect (cancellable, G_CALLBACK (on_portal_cancel), task, NULL); } static void on_bus_get (GObject *source_object, GAsyncResult *result, gpointer user_data) { GDBusConnection *connection; GTask *task = G_TASK (user_data); InitClosure *init = g_task_get_task_data (task); GUnixFDList *fd_list; gint fds[2]; gint fd_index; GVariantBuilder options; GError *error = NULL; gchar *token; connection = g_bus_get_finish (result, &error); if (connection == NULL) { g_task_return_error (task, error); g_object_unref (task); return; } token = g_strdup_printf ("libsecret%d", g_random_int_range (0, G_MAXINT)); init->connection = connection; init->sender = g_strdup (g_dbus_connection_get_unique_name (connection) + 1); /* We modify the string in place, see * https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Request.html */ g_strdelimit (init->sender, ".", '_'); init->request_path = g_strconcat (PORTAL_REQUEST_PATH_PREFIX, init->sender, "/", token, NULL); if (!g_unix_open_pipe (fds, FD_CLOEXEC, &error)) { g_object_unref (connection); g_task_return_error (task, error); g_object_unref (task); g_free (token); return; } fd_list = g_unix_fd_list_new (); fd_index = g_unix_fd_list_append (fd_list, fds[1], &error); close (fds[1]); if (fd_index < 0) { close (fds[0]); g_object_unref (fd_list); g_object_unref (connection); g_task_return_error (task, error); g_object_unref (task); g_free (token); return; } init->stream = g_unix_input_stream_new (fds[0], TRUE); g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&options, "{sv}", "handle_token", g_variant_new_string (token)); init->portal_signal_id = g_dbus_connection_signal_subscribe (connection, PORTAL_BUS_NAME, PORTAL_REQUEST_INTERFACE, "Response", init->request_path, NULL, G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, on_portal_response, task, NULL); g_dbus_connection_call_with_unix_fd_list (connection, PORTAL_BUS_NAME, PORTAL_OBJECT_PATH, PORTAL_SECRET_INTERFACE, "RetrieveSecret", g_variant_new ("(h@a{sv})", fd_index, g_variant_builder_end (&options)), G_VARIANT_TYPE ("(o)"), G_DBUS_CALL_FLAGS_NONE, -1, fd_list, g_task_get_cancellable (task), on_portal_retrieve_secret, task); g_object_unref (fd_list); g_free (token); } #ifdef WITH_TPM static GBytes * load_password_from_tpm (GFile *file, GCancellable *cancellable, GError **error) { EggTpm2Context *context = NULL; char *path = NULL; char *tpm2_file_path = NULL; GFile *tpm2_file = NULL; gboolean status; GBytes *encrypted = NULL; GBytes *decrypted = NULL; context = egg_tpm2_initialize (error); if (!context) return NULL; path = g_file_get_path (file); tpm2_file_path = g_strdup_printf ("%s.tpm2", path); g_free (path); tpm2_file = g_file_new_for_path (tpm2_file_path); status = g_file_test (tpm2_file_path, G_FILE_TEST_EXISTS); g_free (tpm2_file_path); if (!status) { gconstpointer contents; gsize size; encrypted = egg_tpm2_generate_master_password (context, error); if (!encrypted) return NULL; contents = g_bytes_get_data (encrypted, &size); status = g_file_replace_contents (tpm2_file, contents, size, NULL, FALSE, G_FILE_CREATE_PRIVATE, NULL, cancellable, error); if (!status) goto out; } else { char *contents; gsize length; status = g_file_load_contents (tpm2_file, cancellable, &contents, &length, NULL, error); if (!status) goto out; encrypted = g_bytes_new_take (contents, length); } decrypted = egg_tpm2_decrypt_master_password (context, encrypted, error); out: g_clear_object (&tpm2_file); g_clear_pointer (&encrypted, g_bytes_unref); egg_tpm2_finalize (context); return decrypted; } #endif /* WITH_TPM */ static void secret_file_backend_real_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { const char *envvar = NULL; GFile *file = NULL; SecretValue *password; GTask *task; GError *error = NULL; InitClosure *init; task = g_task_new (initable, cancellable, callback, user_data); file = get_secret_file (cancellable, &error); if (file == NULL) { g_task_return_error (task, g_steal_pointer (&error)); g_object_unref (task); return; } envvar = g_getenv ("SECRET_FILE_TEST_PASSWORD"); if (envvar != NULL && *envvar != '\0') { password = secret_value_new (envvar, -1, "text/plain"); g_async_initable_new_async (SECRET_TYPE_FILE_COLLECTION, io_priority, cancellable, on_collection_new_async, task, "file", file, "password", password, NULL); g_object_unref (file); secret_value_unref (password); } else if (g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS) || g_getenv ("SNAP_NAME") != NULL) { init = g_new0 (InitClosure, 1); init->io_priority = io_priority; init->file = file; if (cancellable) init->cancellable = g_object_ref (cancellable); g_task_set_task_data (task, init, init_closure_free); g_bus_get (G_BUS_TYPE_SESSION, cancellable, on_bus_get, task); } else { #ifdef WITH_TPM GBytes *decrypted = NULL; gconstpointer data; gsize size; decrypted = load_password_from_tpm (file, cancellable, &error); if (!decrypted) { g_task_return_error (task, error); g_object_unref (task); return; } data = g_bytes_get_data (decrypted, &size); password = secret_value_new (data,size, "text/plain"); g_bytes_unref (decrypted); g_async_initable_new_async (SECRET_TYPE_FILE_COLLECTION, io_priority, cancellable, on_collection_new_async, task, "file", file, "password", password, NULL); g_object_unref (file); secret_value_unref (password); return; #else g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "master password is not retrievable"); g_object_unref (task); #endif } } static gboolean secret_file_backend_real_init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, initable), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } static void secret_file_backend_async_initable_iface (GAsyncInitableIface *iface) { iface->init_async = secret_file_backend_real_init_async; iface->init_finish = secret_file_backend_real_init_finish; } static void on_collection_write (GObject *source_object, GAsyncResult *result, gpointer user_data) { SecretFileCollection *collection = SECRET_FILE_COLLECTION (source_object); GTask *task = G_TASK (user_data); GError *error = NULL; if (!secret_file_collection_write_finish (collection, result, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } g_task_return_boolean (task, TRUE); g_object_unref (task); } static void secret_file_backend_real_store (SecretBackend *backend, const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretFileBackend *self = SECRET_FILE_BACKEND (backend); GTask *task; GError *error = NULL; /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; task = g_task_new (self, cancellable, callback, user_data); if (!secret_file_collection_replace (self->collection, attributes, label, value, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } secret_file_collection_write (self->collection, cancellable, on_collection_write, task); } static gboolean secret_file_backend_real_store_finish (SecretBackend *backend, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, backend), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } static void on_retrieve_secret (GObject *source_object, GAsyncResult *result, gpointer user_data) { SecretRetrievable *retrievable = SECRET_RETRIEVABLE (source_object); GTask *task = G_TASK (user_data); SecretValue *value; GError *error; value = secret_retrievable_retrieve_secret_finish (retrievable, result, &error); g_object_unref (retrievable); if (value == NULL) { g_task_return_error (task, error); g_object_unref (task); } g_task_return_pointer (task, value, secret_value_unref); g_object_unref (task); } static void secret_file_backend_real_lookup (SecretBackend *backend, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretFileBackend *self = SECRET_FILE_BACKEND (backend); GTask *task; GList *matches; GVariant *variant; SecretFileItem *item; GError *error = NULL; /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; task = g_task_new (self, cancellable, callback, user_data); matches = secret_file_collection_search (self->collection, attributes); if (matches == NULL) { g_task_return_pointer (task, NULL, NULL); g_object_unref (task); return; } variant = g_variant_ref (matches->data); g_list_free_full (matches, (GDestroyNotify)g_variant_unref); item = _secret_file_item_decrypt (variant, self->collection, &error); g_variant_unref (variant); if (item == NULL) { g_task_return_error (task, error); g_object_unref (task); return; } secret_retrievable_retrieve_secret (SECRET_RETRIEVABLE (item), cancellable, on_retrieve_secret, task); } static SecretValue * secret_file_backend_real_lookup_finish (SecretBackend *backend, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, backend), NULL); return g_task_propagate_pointer (G_TASK (result), error); } static void secret_file_backend_real_clear (SecretBackend *backend, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretFileBackend *self = SECRET_FILE_BACKEND (backend); GTask *task; GError *error = NULL; gboolean ret; /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; task = g_task_new (self, cancellable, callback, user_data); ret = secret_file_collection_clear (self->collection, attributes, &error); if (error != NULL) { g_task_return_error (task, error); g_object_unref (task); return; } /* No need to write as nothing has been removed. */ if (!ret) { g_task_return_boolean (task, FALSE); g_object_unref (task); return; } secret_file_collection_write (self->collection, cancellable, on_collection_write, task); } static gboolean secret_file_backend_real_clear_finish (SecretBackend *backend, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, backend), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } static void unref_objects (gpointer data) { GList *list = data; g_list_free_full (list, g_object_unref); } static void secret_file_backend_real_search (SecretBackend *backend, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretFileBackend *self = SECRET_FILE_BACKEND (backend); GTask *task; GList *matches; GList *results = NULL; GList *l; GError *error = NULL; /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; task = g_task_new (self, cancellable, callback, user_data); matches = secret_file_collection_search (self->collection, attributes); for (l = matches; l; l = g_list_next (l)) { SecretFileItem *item = _secret_file_item_decrypt (l->data, self->collection, &error); if (item == NULL) { g_task_return_error (task, error); g_object_unref (task); return; } results = g_list_append (results, item); } g_list_free_full (matches, (GDestroyNotify)g_variant_unref); g_task_return_pointer (task, results, unref_objects); g_object_unref (task); } static GList * secret_file_backend_real_search_finish (SecretBackend *backend, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, backend), NULL); return g_task_propagate_pointer (G_TASK (result), error); } static void secret_file_backend_backend_iface (SecretBackendInterface *iface) { iface->store = secret_file_backend_real_store; iface->store_finish = secret_file_backend_real_store_finish; iface->lookup = secret_file_backend_real_lookup; iface->lookup_finish = secret_file_backend_real_lookup_finish; iface->clear = secret_file_backend_real_clear; iface->clear_finish = secret_file_backend_real_clear_finish; iface->search = secret_file_backend_real_search; iface->search_finish = secret_file_backend_real_search_finish; } gboolean _secret_file_backend_check_portal_version (void) { GDBusConnection *connection; GVariant *ret; GVariant *value; guint32 version; GError *error = NULL; connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (!connection) { g_warning ("couldn't get session bus: %s", error->message); g_error_free (error); return FALSE; } ret = g_dbus_connection_call_sync (connection, PORTAL_BUS_NAME, PORTAL_OBJECT_PATH, "org.freedesktop.DBus.Properties", "Get", g_variant_new ("(ss)", PORTAL_SECRET_INTERFACE, "version"), G_VARIANT_TYPE ("(v)"), 0, -1, NULL, &error); g_object_unref (connection); if (!ret) { g_info ("secret portal is not available: %s", error->message); g_error_free (error); return FALSE; } g_variant_get (ret, "(v)", &value); g_variant_unref (ret); version = g_variant_get_uint32 (value); g_variant_unref (value); if (version != PORTAL_SECRET_VERSION) { g_info ("secret portal version mismatch: %u != %u", version, PORTAL_SECRET_VERSION); return FALSE; } return TRUE; } 07070100000062000081A400000000000000000000000167D9F0D9000003BE000000000000000000000000000000000000003100000000libsecret-0.21.7/libsecret/secret-file-backend.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_FILE_BACKEND_H__ #define __SECRET_FILE_BACKEND_H__ #include G_BEGIN_DECLS #define SECRET_TYPE_FILE_BACKEND (secret_file_backend_get_type ()) G_DECLARE_FINAL_TYPE (SecretFileBackend, secret_file_backend, SECRET, FILE_BACKEND, GObject) gboolean _secret_file_backend_check_portal_version (void); G_END_DECLS #endif /* __SECRET_FILE_BACKEND_H__ */ 07070100000063000081A400000000000000000000000167D9F0D900005122000000000000000000000000000000000000003400000000libsecret-0.21.7/libsecret/secret-file-collection.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #include "config.h" #include "secret-file-collection.h" #include "egg/egg-keyring1.h" #include "egg/egg-secure-memory.h" EGG_SECURE_DECLARE (secret_file_collection); #ifdef WITH_GCRYPT #include "egg/egg-libgcrypt.h" #endif #define KEYRING_FILE_HEADER "GnomeKeyring\n\r\0\n" #define KEYRING_FILE_HEADER_LEN 16 #define MAJOR_VERSION 1 #define MINOR_VERSION 0 struct _SecretFileCollection { GObject parent; GFile *file; gchar *etag; SecretValue *password; GBytes *salt; guint32 iteration_count; GDateTime *modified; guint64 usage_count; GBytes *key; GVariant *items; guint64 file_last_modified; }; static void secret_file_collection_async_initable_iface (GAsyncInitableIface *iface); G_DEFINE_TYPE_WITH_CODE (SecretFileCollection, secret_file_collection, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_file_collection_async_initable_iface); ); enum { PROP_0, PROP_FILE, PROP_PASSWORD }; static guint64 get_file_last_modified (SecretFileCollection *self) { GFileInfo *info; guint64 res; info = g_file_query_info (self->file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL); if (info == NULL) return 0; res = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); g_object_unref (info); return res; } static void secret_file_collection_init (SecretFileCollection *self) { } static void secret_file_collection_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { SecretFileCollection *self = SECRET_FILE_COLLECTION (object); switch (prop_id) { case PROP_FILE: self->file = g_value_dup_object (value); break; case PROP_PASSWORD: self->password = g_value_dup_boxed (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void secret_file_collection_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void secret_file_collection_finalize (GObject *object) { SecretFileCollection *self = SECRET_FILE_COLLECTION (object); g_object_unref (self->file); g_free (self->etag); secret_value_unref (self->password); g_clear_pointer (&self->salt, g_bytes_unref); g_clear_pointer (&self->key, g_bytes_unref); g_clear_pointer (&self->items, g_variant_unref); g_clear_pointer (&self->modified, g_date_time_unref); G_OBJECT_CLASS (secret_file_collection_parent_class)->finalize (object); } static void secret_file_collection_class_init (SecretFileCollectionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = secret_file_collection_set_property; object_class->get_property = secret_file_collection_get_property; object_class->finalize = secret_file_collection_finalize; g_object_class_install_property (object_class, PROP_FILE, g_param_spec_object ("file", "File", "File", G_TYPE_FILE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_PASSWORD, g_param_spec_boxed ("password", "password", "Password", SECRET_TYPE_VALUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); #ifdef WITH_GCRYPT egg_libgcrypt_initialize (); #endif } static gboolean load_contents (SecretFileCollection *self, gchar *contents, /* takes ownership */ gsize length, GError **error) { gchar *p; GVariant *variant; GVariant *salt_array; guint32 salt_size; guint32 iteration_count; guint64 modified_time; guint64 usage_count; gconstpointer data; gsize n_data; const gchar *password; gsize n_password; p = contents; if (length < KEYRING_FILE_HEADER_LEN || memcmp (p, KEYRING_FILE_HEADER, KEYRING_FILE_HEADER_LEN) != 0) { g_set_error_literal (error, SECRET_ERROR, SECRET_ERROR_INVALID_FILE_FORMAT, "file header mismatch"); return FALSE; } p += KEYRING_FILE_HEADER_LEN; length -= KEYRING_FILE_HEADER_LEN; if (length < 2 || *p != MAJOR_VERSION || *(p + 1) != MINOR_VERSION) { g_set_error_literal (error, SECRET_ERROR, SECRET_ERROR_INVALID_FILE_FORMAT, "version mismatch"); return FALSE; } p += 2; length -= 2; variant = g_variant_new_from_data (G_VARIANT_TYPE ("(uayutua(a{say}ay))"), p, length, TRUE, g_free, contents); g_variant_get (variant, "(u@ayutu@a(a{say}ay))", &salt_size, &salt_array, &iteration_count, &modified_time, &usage_count, &self->items); salt_size = GUINT32_FROM_LE(salt_size); iteration_count = GUINT32_FROM_LE(iteration_count); modified_time = GUINT64_FROM_LE(modified_time); usage_count = GUINT32_FROM_LE(usage_count); self->iteration_count = iteration_count; self->modified = g_date_time_new_from_unix_utc (modified_time); self->usage_count = usage_count; data = g_variant_get_fixed_array (salt_array, &n_data, sizeof(guint8)); g_assert (n_data == salt_size); self->salt = g_bytes_new (data, n_data); g_variant_unref (salt_array); g_variant_unref (variant); password = secret_value_get (self->password, &n_password); self->key = egg_keyring1_derive_key (password, n_password, self->salt, self->iteration_count); if (!self->key) { g_set_error_literal (error, SECRET_ERROR, SECRET_ERROR_PROTOCOL, "couldn't derive key"); return FALSE; } return TRUE; } static gboolean init_empty_file (SecretFileCollection *self, GError **error) { GVariantBuilder builder; const gchar *password; gsize n_password; guint8 salt[SALT_SIZE]; egg_keyring1_create_nonce (salt, sizeof(salt)); self->salt = g_bytes_new (salt, sizeof(salt)); self->iteration_count = ITERATION_COUNT; self->modified = g_date_time_new_now_utc (); self->usage_count = 0; password = secret_value_get (self->password, &n_password); self->key = egg_keyring1_derive_key (password, n_password, self->salt, self->iteration_count); if (!self->key) { g_set_error_literal (error, SECRET_ERROR, SECRET_ERROR_PROTOCOL, "couldn't derive key"); return FALSE; } g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(a{say}ay)")); self->items = g_variant_builder_end (&builder); g_variant_ref_sink (self->items); return TRUE; } static void ensure_up_to_date (SecretFileCollection *self) { guint64 last_modified; last_modified = get_file_last_modified (self); if (last_modified != self->file_last_modified) { gchar *contents = NULL; gsize length = 0; gboolean success; GError *error = NULL; gchar *etag = NULL; self->file_last_modified = last_modified; success = g_file_load_contents (self->file, NULL, &contents, &length, &etag, &error); if (success) { g_clear_pointer (&self->etag, g_free); self->etag = g_steal_pointer (&etag); } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { g_clear_error (&error); success = init_empty_file (self, &error); } if (success) success = load_contents (self, contents, length, &error); if (!success) g_debug ("Failed to load file contents: %s", error ? error->message : "Unknown error"); g_clear_error (&error); } } static void on_load_contents (GObject *source_object, GAsyncResult *result, gpointer user_data) { GFile *file = G_FILE (source_object); GTask *task = G_TASK (user_data); SecretFileCollection *self = g_task_get_source_object (task); gchar *contents; gsize length; GError *error = NULL; gboolean ret; gchar *etag = NULL; self->file_last_modified = get_file_last_modified (self); ret = g_file_load_contents_finish (file, result, &contents, &length, &etag, &error); if (!ret) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { g_clear_error (&error); if (init_empty_file (self, &error)) { g_task_return_boolean (task, TRUE); g_object_unref (task); return; } } g_task_return_error (task, error); g_object_unref (task); return; } g_clear_pointer (&self->etag, g_free); self->etag = g_steal_pointer (&etag); ret = load_contents (self, contents, length, &error); if (ret) g_task_return_boolean (task, ret); else g_task_return_error (task, error); g_object_unref (task); } static void secret_file_collection_real_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretFileCollection *self = SECRET_FILE_COLLECTION (initable); GTask *task; task = g_task_new (initable, cancellable, callback, user_data); g_file_load_contents_async (self->file, cancellable, on_load_contents, task); } static gboolean secret_file_collection_real_init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, initable), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } static void secret_file_collection_async_initable_iface (GAsyncInitableIface *iface) { iface->init_async = secret_file_collection_real_init_async; iface->init_finish = secret_file_collection_real_init_finish; } static GVariant * hash_attributes (SecretFileCollection *self, GHashTable *attributes) { GVariantBuilder builder; guint8 buffer[MAC_SIZE]; GList *keys; GList *l; g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{say}")); keys = g_hash_table_get_keys (attributes); keys = g_list_sort (keys, (GCompareFunc) g_strcmp0); for (l = keys; l; l = g_list_next (l)) { const gchar *value; GVariant *variant; value = g_hash_table_lookup (attributes, l->data); if (!egg_keyring1_calculate_mac (self->key, (const guint8 *)value, strlen (value), buffer)) { g_list_free (keys); return NULL; } variant = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buffer, MAC_SIZE, sizeof(guint8)); g_variant_builder_add (&builder, "{s@ay}", l->data, variant); } g_list_free (keys); return g_variant_builder_end (&builder); } static gboolean hashed_attributes_match (SecretFileCollection *self, GVariant *hashed_attributes, GHashTable *attributes) { GHashTableIter iter; GVariant *hashed_attribute = NULL; gpointer key; gpointer value; g_hash_table_iter_init (&iter, attributes); while (g_hash_table_iter_next (&iter, &key, &value)) { const guint8 *data; gsize n_data; if (!g_variant_lookup (hashed_attributes, key, "@ay", &hashed_attribute)) return FALSE; data = g_variant_get_fixed_array (hashed_attribute, &n_data, sizeof(guint8)); if (n_data != MAC_SIZE) { g_variant_unref (hashed_attribute); return FALSE; } if (!egg_keyring1_verify_mac (self->key, value, strlen ((char *)value), data)) { g_variant_unref (hashed_attribute); return FALSE; } g_variant_unref (hashed_attribute); } return TRUE; } gboolean secret_file_collection_replace (SecretFileCollection *self, GHashTable *attributes, const gchar *label, SecretValue *value, GError **error) { GVariantBuilder builder; GVariant *hashed_attributes; GVariantIter iter; GVariant *child; SecretFileItem *item; GVariant *serialized_item; guint8 *data = NULL; gsize n_data; gsize n_padded; GVariant *variant; GDateTime *created = NULL; GDateTime *modified; ensure_up_to_date (self); hashed_attributes = hash_attributes (self, attributes); if (!hashed_attributes) { g_set_error (error, SECRET_ERROR, SECRET_ERROR_PROTOCOL, "couldn't calculate mac"); return FALSE; } /* Filter out the existing item */ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(a{say}ay)")); g_variant_iter_init (&iter, self->items); while ((child = g_variant_iter_next_value (&iter)) != NULL) { GVariant *_hashed_attributes; g_variant_get (child, "(@a{say}ay)", &_hashed_attributes, NULL); if (g_variant_equal (hashed_attributes, _hashed_attributes)) { SecretFileItem *existing = _secret_file_item_decrypt (child, self, error); guint64 created_time; if (existing == NULL) { g_variant_builder_clear (&builder); g_variant_unref (child); g_variant_unref (_hashed_attributes); return FALSE; } g_object_get (existing, "created", &created_time, NULL); g_object_unref (existing); created = g_date_time_new_from_unix_utc (created_time); } else { g_variant_builder_add_value (&builder, child); } g_variant_unref (child); g_variant_unref (_hashed_attributes); } modified = g_date_time_new_now_utc (); if (created == NULL) created = g_date_time_ref (modified); /* Create a new item and append it */ item = g_object_new (SECRET_TYPE_FILE_ITEM, "attributes", attributes, "label", label, "value", value, "created", g_date_time_to_unix (created), "modified", g_date_time_to_unix (modified), NULL); g_date_time_unref (created); g_date_time_unref (modified); serialized_item = secret_file_item_serialize (item); g_object_unref (item); /* Encrypt the item with PKCS #7 padding */ n_data = g_variant_get_size (serialized_item); n_padded = ((n_data + CIPHER_BLOCK_SIZE) / CIPHER_BLOCK_SIZE) * CIPHER_BLOCK_SIZE; data = egg_secure_alloc (n_padded + IV_SIZE + MAC_SIZE); g_variant_store (serialized_item, data); g_variant_unref (serialized_item); memset (data + n_data, n_padded - n_data, n_padded - n_data); if (!egg_keyring1_encrypt (self->key, data, n_padded)) { egg_secure_free (data); g_set_error (error, SECRET_ERROR, SECRET_ERROR_PROTOCOL, "couldn't encrypt item"); return FALSE; } if (!egg_keyring1_calculate_mac (self->key, data, n_padded + IV_SIZE, data + n_padded + IV_SIZE)) { egg_secure_free (data); g_set_error (error, SECRET_ERROR, SECRET_ERROR_PROTOCOL, "couldn't calculate mac"); return FALSE; } self->usage_count++; g_date_time_unref (self->modified); self->modified = g_date_time_new_now_utc (); variant = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, n_padded + IV_SIZE + MAC_SIZE, TRUE, egg_secure_free, data); variant = g_variant_new ("(@a{say}@ay)", hashed_attributes, variant); g_variant_builder_add_value (&builder, variant); g_variant_unref (self->items); self->items = g_variant_builder_end (&builder); g_variant_ref_sink (self->items); return TRUE; } GList * secret_file_collection_search (SecretFileCollection *self, GHashTable *attributes) { GVariantIter iter; GVariant *child; GList *result = NULL; ensure_up_to_date (self); g_variant_iter_init (&iter, self->items); while ((child = g_variant_iter_next_value (&iter)) != NULL) { GVariant *hashed_attributes; gboolean matched; g_variant_get (child, "(@a{say}ay)", &hashed_attributes, NULL); matched = hashed_attributes_match (self, hashed_attributes, attributes); g_variant_unref (hashed_attributes); if (matched) result = g_list_append (result, g_variant_ref (child)); g_variant_unref (child); } return result; } SecretFileItem * _secret_file_item_decrypt (GVariant *encrypted, SecretFileCollection *collection, GError **error) { GVariant *blob; gconstpointer padded; gsize n_data; gsize n_padded; guint8 *data; SecretFileItem *item; GVariant *serialized_item; g_variant_get (encrypted, "(a{say}@ay)", NULL, &blob); /* Decrypt the item */ padded = g_variant_get_fixed_array (blob, &n_padded, sizeof(guint8)); data = egg_secure_alloc (n_padded); memcpy (data, padded, n_padded); g_variant_unref (blob); if (n_padded < IV_SIZE + MAC_SIZE) { egg_secure_free (data); g_set_error (error, SECRET_ERROR, SECRET_ERROR_PROTOCOL, "couldn't calculate mac"); return FALSE; } n_padded -= MAC_SIZE; if (!egg_keyring1_verify_mac (collection->key, data, n_padded, data + n_padded)) { egg_secure_free (data); g_set_error (error, SECRET_ERROR, SECRET_ERROR_PROTOCOL, "couldn't calculate mac"); return FALSE; } n_padded -= IV_SIZE; if (!egg_keyring1_decrypt (collection->key, data, n_padded)) { egg_secure_free (data); g_set_error (error, SECRET_ERROR, SECRET_ERROR_PROTOCOL, "couldn't decrypt item"); return NULL; } /* Remove PKCS #7 padding */ n_data = n_padded - data[n_padded - 1]; serialized_item = g_variant_new_from_data (G_VARIANT_TYPE ("(a{ss}sttay)"), data, n_data, TRUE, egg_secure_free, data); item = secret_file_item_deserialize (serialized_item); g_variant_unref (serialized_item); return item; } gboolean secret_file_collection_clear (SecretFileCollection *self, GHashTable *attributes, GError **error) { GVariantBuilder builder; GVariantIter items; GVariant *child; gboolean removed = FALSE; ensure_up_to_date (self); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(a{say}ay)")); g_variant_iter_init (&items, self->items); while ((child = g_variant_iter_next_value (&items)) != NULL) { GVariant *hashed_attributes; gboolean matched; g_variant_get (child, "(@a{say}ay)", &hashed_attributes, NULL); matched = hashed_attributes_match (self, hashed_attributes, attributes); g_variant_unref (hashed_attributes); if (matched) removed = TRUE; else g_variant_builder_add_value (&builder, child); g_variant_unref (child); } g_variant_unref (self->items); self->items = g_variant_builder_end (&builder); g_variant_ref_sink (self->items); return removed; } static void on_replace_contents (GObject *source_object, GAsyncResult *result, gpointer user_data) { GFile *file = G_FILE (source_object); GTask *task = G_TASK (user_data); SecretFileCollection *self = g_task_get_source_object (task); GError *error = NULL; gchar *etag = NULL; if (!g_file_replace_contents_finish (file, result, &etag, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } self->file_last_modified = get_file_last_modified (self); g_clear_pointer (&self->etag, g_free); self->etag = g_steal_pointer (&etag); g_task_return_boolean (task, TRUE); g_object_unref (task); } void secret_file_collection_write (SecretFileCollection *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; guint8 *contents; gsize n_contents; guint8 *p; GVariant *salt_array; GVariant *variant; salt_array = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, g_bytes_get_data (self->salt, NULL), g_bytes_get_size (self->salt), sizeof(guint8)); variant = g_variant_new ("(u@ayutu@a(a{say}ay))", GUINT32_TO_LE(g_bytes_get_size (self->salt)), salt_array, GUINT32_TO_LE(self->iteration_count), GUINT64_TO_LE(g_date_time_to_unix (self->modified)), GUINT32_TO_LE(self->usage_count), self->items); g_variant_get_data (variant); /* force serialize */ n_contents = KEYRING_FILE_HEADER_LEN + 2 + g_variant_get_size (variant); contents = g_new (guint8, n_contents); p = contents; memcpy (p, KEYRING_FILE_HEADER, KEYRING_FILE_HEADER_LEN); p += KEYRING_FILE_HEADER_LEN; *p++ = MAJOR_VERSION; *p++ = MINOR_VERSION; g_variant_store (variant, p); g_variant_unref (variant); task = g_task_new (self, cancellable, callback, user_data); g_task_set_task_data (task, contents, g_free); g_file_replace_contents_async (self->file, (gchar *) contents, n_contents, self->etag, TRUE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, cancellable, on_replace_contents, task); } gboolean secret_file_collection_write_finish (SecretFileCollection *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, self), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } 07070100000064000081A400000000000000000000000167D9F0D900000A57000000000000000000000000000000000000003400000000libsecret-0.21.7/libsecret/secret-file-collection.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_FILE_COLLECTION_H__ #define __SECRET_FILE_COLLECTION_H__ #include "secret-file-item.h" #include "secret-value.h" G_BEGIN_DECLS #define SECRET_TYPE_FILE_COLLECTION (secret_file_collection_get_type ()) G_DECLARE_FINAL_TYPE (SecretFileCollection, secret_file_collection, SECRET, FILE_COLLECTION, GObject) gboolean secret_file_collection_replace (SecretFileCollection *self, GHashTable *attributes, const gchar *label, SecretValue *value, GError **error); GList *secret_file_collection_search (SecretFileCollection *self, GHashTable *attributes); gboolean secret_file_collection_clear (SecretFileCollection *self, GHashTable *attributes, GError **error); void secret_file_collection_write (SecretFileCollection *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_file_collection_write_finish (SecretFileCollection *self, GAsyncResult *result, GError **error); SecretFileItem *_secret_file_item_decrypt (GVariant *encrypted, SecretFileCollection *collection, GError **error); G_END_DECLS #endif /* __SECRET_FILE_COLLECTION_H__ */ 07070100000065000081A400000000000000000000000167D9F0D900001A4B000000000000000000000000000000000000002E00000000libsecret-0.21.7/libsecret/secret-file-item.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #include "config.h" #include "secret-file-item.h" #include "secret-retrievable.h" #include "secret-value.h" struct _SecretFileItem { GObject parent; GHashTable *attributes; gchar *label; guint64 created; guint64 modified; SecretValue *value; GVariant *encrypted; }; static void secret_file_item_retrievable_iface (SecretRetrievableInterface *iface); G_DEFINE_TYPE_WITH_CODE (SecretFileItem, secret_file_item, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (SECRET_TYPE_RETRIEVABLE, secret_file_item_retrievable_iface); ); enum { PROP_0, PROP_ATTRIBUTES, PROP_LABEL, PROP_CREATED, PROP_MODIFIED, PROP_VALUE }; static void secret_file_item_init (SecretFileItem *self) { } static void secret_file_item_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { SecretFileItem *self = SECRET_FILE_ITEM (object); switch (prop_id) { case PROP_ATTRIBUTES: self->attributes = g_value_dup_boxed (value); break; case PROP_LABEL: self->label = g_value_dup_string (value); break; case PROP_CREATED: self->created = g_value_get_uint64 (value); break; case PROP_MODIFIED: self->modified = g_value_get_uint64 (value); break; case PROP_VALUE: self->value = g_value_dup_boxed (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void secret_file_item_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { SecretFileItem *self = SECRET_FILE_ITEM (object); switch (prop_id) { case PROP_ATTRIBUTES: g_value_set_boxed (value, self->attributes); break; case PROP_LABEL: g_value_set_string (value, self->label); break; case PROP_CREATED: g_value_set_uint64 (value, self->created); break; case PROP_MODIFIED: g_value_set_uint64 (value, self->modified); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void secret_file_item_finalize (GObject *object) { SecretFileItem *self = SECRET_FILE_ITEM (object); g_hash_table_unref (self->attributes); g_free (self->label); secret_value_unref (self->value); G_OBJECT_CLASS (secret_file_item_parent_class)->finalize (object); } static void secret_file_item_class_init (SecretFileItemClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = secret_file_item_set_property; gobject_class->get_property = secret_file_item_get_property; gobject_class->finalize = secret_file_item_finalize; g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes"); g_object_class_override_property (gobject_class, PROP_LABEL, "label"); g_object_class_override_property (gobject_class, PROP_CREATED, "created"); g_object_class_override_property (gobject_class, PROP_MODIFIED, "modified"); g_object_class_install_property (gobject_class, PROP_VALUE, g_param_spec_boxed ("value", "Value", "Value", SECRET_TYPE_VALUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); } static void secret_file_item_retrieve_secret (SecretRetrievable *retrievable, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretFileItem *self = SECRET_FILE_ITEM (retrievable); GTask *task = g_task_new (retrievable, cancellable, callback, user_data); g_task_return_pointer (task, secret_value_ref (self->value), secret_value_unref); g_object_unref (task); } static SecretValue * secret_file_item_retrieve_secret_finish (SecretRetrievable *retrievable, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, retrievable), NULL); return g_task_propagate_pointer (G_TASK (result), error); } static void secret_file_item_retrievable_iface (SecretRetrievableInterface *iface) { iface->retrieve_secret = secret_file_item_retrieve_secret; iface->retrieve_secret_finish = secret_file_item_retrieve_secret_finish; } static GHashTable * variant_to_attributes (GVariant *variant) { GVariantIter iter; gchar *key; gchar *value; GHashTable *attributes; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_variant_iter_init (&iter, variant); while (g_variant_iter_next (&iter, "{ss}", &key, &value)) g_hash_table_insert (attributes, key, value); return attributes; } SecretFileItem * secret_file_item_deserialize (GVariant *serialized) { GVariant *attributes_variant; GHashTable *attributes; const gchar *label; guint64 created; guint64 modified; GVariant *array; const gchar *secret; gsize n_secret; SecretValue *value; SecretFileItem *result; g_variant_get (serialized, "(@a{ss}&stt@ay)", &attributes_variant, &label, &created, &modified, &array); secret = g_variant_get_fixed_array (array, &n_secret, sizeof(gchar)); value = secret_value_new (secret, n_secret, "text/plain"); attributes = variant_to_attributes (attributes_variant); g_variant_unref (attributes_variant); result = g_object_new (SECRET_TYPE_FILE_ITEM, "attributes", attributes, "label", label, "created", created, "modified", modified, "value", value, NULL); g_hash_table_unref (attributes); g_variant_unref (array); secret_value_unref (value); return result; } GVariant * secret_file_item_serialize (SecretFileItem *self) { GVariantBuilder builder; GHashTableIter iter; gpointer key; gpointer value; GVariant *variant; const gchar *secret; gsize n_secret; g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); g_hash_table_iter_init (&iter, self->attributes); while (g_hash_table_iter_next (&iter, &key, &value)) g_variant_builder_add (&builder, "{ss}", key, value); secret = secret_value_get (self->value, &n_secret); variant = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, secret, n_secret, sizeof(guint8)); variant = g_variant_new ("(@a{ss}stt@ay)", g_variant_builder_end (&builder), self->label, self->created, self->modified, variant); g_variant_get_data (variant); /* force serialize */ return g_variant_ref_sink (variant); } 07070100000066000081A400000000000000000000000167D9F0D9000003ED000000000000000000000000000000000000002E00000000libsecret-0.21.7/libsecret/secret-file-item.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_FILE_ITEM_H__ #define __SECRET_FILE_ITEM_H__ #include G_BEGIN_DECLS #define SECRET_TYPE_FILE_ITEM (secret_file_item_get_type ()) G_DECLARE_FINAL_TYPE (SecretFileItem, secret_file_item, SECRET, FILE_ITEM, GObject) SecretFileItem *secret_file_item_deserialize (GVariant *serialized); GVariant *secret_file_item_serialize (SecretFileItem *self); G_END_DECLS #endif /* __SECRET_FILE_ITEM_H__ */ 07070100000067000081A400000000000000000000000167D9F0D90000ED06000000000000000000000000000000000000002900000000libsecret-0.21.7/libsecret/secret-item.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-collection.h" #include "secret-dbus-generated.h" #include "secret-item.h" #include "secret-paths.h" #include "secret-private.h" #include "secret-retrievable.h" #include "secret-service.h" #include "secret-types.h" #include "secret-value.h" #include "libsecret/secret-enum-types.h" #include /** * SecretItem: * * A secret item * * #SecretItem represents a secret item stored in the Secret Service. * * Each item has a value, represented by a [struct@Value], which can be * retrieved by [method@Item.get_secret] or set by [method@Item.set_secret]. * The item is only available when the item is not locked. * * Items can be locked or unlocked using the [method@Service.lock] or * [method@Service.unlock] functions. The Secret Service may not be able to * unlock individual items, and may unlock an entire collection when a single * item is unlocked. * * Each item has a set of attributes, which are used to locate the item later. * These are not stored or transferred in a secure manner. Each attribute has * a string name and a string value. Use [method@Service.search] to search for * items based on their attributes, and [method@Item.set_attributes] to change * the attributes associated with an item. * * Items can be created with [func@Item.create] or [method@Service.store]. * * Stability: Stable */ /** * SecretItemClass: * @parent_class: the parent class * * The class for #SecretItem. */ /** * SecretItemFlags: * @SECRET_ITEM_NONE: no flags * @SECRET_ITEM_LOAD_SECRET: a secret has been (or should be) loaded for #SecretItem * * Flags which determine which parts of the #SecretItem proxy are initialized. */ /** * SecretItemCreateFlags: * @SECRET_ITEM_CREATE_NONE: no flags * @SECRET_ITEM_CREATE_REPLACE: replace an item with the same attributes. * * Flags for [func@Item.create]. */ enum { PROP_0, PROP_SERVICE, PROP_FLAGS, PROP_ATTRIBUTES, PROP_LABEL, PROP_LOCKED, PROP_CREATED, PROP_MODIFIED }; struct _SecretItemPrivate { /* No changes between construct and finalize */ SecretService *service; SecretItemFlags init_flags; /* Locked by mutex */ GMutex mutex; SecretValue *value; gint disposed; }; static SecretRetrievableInterface *secret_item_retrievable_parent_iface = NULL; static GInitableIface *secret_item_initable_parent_iface = NULL; static GAsyncInitableIface *secret_item_async_initable_parent_iface = NULL; static void secret_item_retrievable_iface (SecretRetrievableInterface *iface); static void secret_item_initable_iface (GInitableIface *iface); static void secret_item_async_initable_iface (GAsyncInitableIface *iface); G_DEFINE_TYPE_WITH_CODE (SecretItem, secret_item, G_TYPE_DBUS_PROXY, G_ADD_PRIVATE (SecretItem) G_IMPLEMENT_INTERFACE (SECRET_TYPE_RETRIEVABLE, secret_item_retrievable_iface); G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_item_initable_iface); G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_item_async_initable_iface); ); static void secret_item_init (SecretItem *self) { self->pv = secret_item_get_instance_private (self); g_mutex_init (&self->pv->mutex); } static void on_set_attributes (GObject *source, GAsyncResult *result, gpointer user_data) { SecretItem *self = SECRET_ITEM (user_data); GError *error = NULL; if (!g_atomic_int_get (&self->pv->disposed)) { secret_item_set_attributes_finish (self, result, &error); if (error != NULL) { g_warning ("couldn't set SecretItem Attributes: %s", error->message); g_error_free (error); } } g_object_unref (self); } static void on_set_label (GObject *source, GAsyncResult *result, gpointer user_data) { SecretItem *self = SECRET_ITEM (user_data); GError *error = NULL; if (!g_atomic_int_get (&self->pv->disposed)) { secret_item_set_label_finish (self, result, &error); if (error != NULL) { g_warning ("couldn't set SecretItem Label: %s", error->message); g_error_free (error); } } g_object_unref (self); } static void item_take_service (SecretItem *self, SecretService *service) { if (service == NULL) return; g_return_if_fail (self->pv->service == NULL); self->pv->service = service; g_object_add_weak_pointer (G_OBJECT (self->pv->service), (gpointer *)&self->pv->service); /* Yes, we expect that the service will stay around */ g_object_unref (service); } static void secret_item_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { SecretItem *self = SECRET_ITEM (obj); switch (prop_id) { case PROP_SERVICE: item_take_service (self, g_value_dup_object (value)); break; case PROP_FLAGS: self->pv->init_flags = g_value_get_flags (value); break; case PROP_ATTRIBUTES: secret_item_set_attributes (self, NULL, g_value_get_boxed (value), NULL, on_set_attributes, g_object_ref (self)); break; case PROP_LABEL: secret_item_set_label (self, g_value_get_string (value), NULL, on_set_label, g_object_ref (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void secret_item_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { SecretItem *self = SECRET_ITEM (obj); switch (prop_id) { case PROP_SERVICE: g_value_set_object (value, self->pv->service); break; case PROP_FLAGS: g_value_set_flags (value, secret_item_get_flags (self)); break; case PROP_ATTRIBUTES: g_value_take_boxed (value, secret_item_get_attributes (self)); break; case PROP_LABEL: g_value_take_string (value, secret_item_get_label (self)); break; case PROP_LOCKED: g_value_set_boolean (value, secret_item_get_locked (self)); break; case PROP_CREATED: g_value_set_uint64 (value, secret_item_get_created (self)); break; case PROP_MODIFIED: g_value_set_uint64 (value, secret_item_get_modified (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void secret_item_dispose (GObject *obj) { SecretItem *self = SECRET_ITEM (obj); g_atomic_int_inc (&self->pv->disposed); G_OBJECT_CLASS (secret_item_parent_class)->dispose (obj); } static void secret_item_finalize (GObject *obj) { SecretItem *self = SECRET_ITEM (obj); if (self->pv->service) g_object_remove_weak_pointer (G_OBJECT (self->pv->service), (gpointer *)&self->pv->service); if (self->pv->value != NULL) secret_value_unref (self->pv->value); g_mutex_clear (&self->pv->mutex); G_OBJECT_CLASS (secret_item_parent_class)->finalize (obj); } static void handle_property_changed (GObject *object, const gchar *property_name) { if (g_str_equal (property_name, "Attributes")) g_object_notify (object, "attributes"); else if (g_str_equal (property_name, "Label")) g_object_notify (object, "label"); else if (g_str_equal (property_name, "Locked")) g_object_notify (object, "locked"); else if (g_str_equal (property_name, "Created")) g_object_notify (object, "created"); else if (g_str_equal (property_name, "Modified")) g_object_notify (object, "modified"); } static void secret_item_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, const gchar* const *invalidated_properties) { GObject *obj = G_OBJECT (proxy); gchar *property_name; GVariantIter iter; GVariant *value; g_object_freeze_notify (obj); g_variant_iter_init (&iter, changed_properties); while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value)) handle_property_changed (obj, property_name); g_object_thaw_notify (obj); } static void secret_item_class_init (SecretItemClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass); gobject_class->get_property = secret_item_get_property; gobject_class->set_property = secret_item_set_property; gobject_class->dispose = secret_item_dispose; gobject_class->finalize = secret_item_finalize; proxy_class->g_properties_changed = secret_item_properties_changed; /** * SecretItem:service: (attributes org.gtk.Property.get=secret_item_get_service) * * The [class@Service] object that this item is associated with and * uses to interact with the actual D-Bus Secret Service. */ g_object_class_install_property (gobject_class, PROP_SERVICE, g_param_spec_object ("service", "Service", "Secret Service", SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * SecretItem:flags: (attributes org.gtk.Property.get=secret_item_get_flags) * * A set of flags describing which parts of the secret item have * been initialized. */ g_object_class_install_property (gobject_class, PROP_FLAGS, g_param_spec_flags ("flags", "Flags", "Item flags", secret_item_flags_get_type (), SECRET_ITEM_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * SecretItem:attributes: (type GLib.HashTable(utf8,utf8)) (transfer full) * * The attributes set on this item. Attributes are used to locate an * item. * * They are not guaranteed to be stored or transferred securely. */ g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes"); /** * SecretItem:label: * * The human readable label for the item. * * Setting this property will result in the label of the item being * set asynchronously. To properly track the changing of the label use the * [method@Item.set_label] function. */ g_object_class_override_property (gobject_class, PROP_LABEL, "label"); /** * SecretItem:locked: (attributes org.gtk.Property.get=secret_item_get_locked) * * Whether the item is locked or not. * * An item may not be independently lockable separate from other items in * its collection. * * To lock or unlock a item use the [method@Service.lock] or * [method@Service.unlock] functions. */ g_object_class_install_property (gobject_class, PROP_LOCKED, g_param_spec_boolean ("locked", "Locked", "Item locked", TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * SecretItem:created: * * The date and time (in seconds since the UNIX epoch) that this * item was created. */ g_object_class_override_property (gobject_class, PROP_CREATED, "created"); /** * SecretItem:modified: * * The date and time (in seconds since the UNIX epoch) that this * item was last modified. */ g_object_class_override_property (gobject_class, PROP_MODIFIED, "modified"); } static gboolean item_ensure_for_flags_sync (SecretItem *self, SecretItemFlags flags, GCancellable *cancellable, GError **error) { if (flags & SECRET_ITEM_LOAD_SECRET && !secret_item_get_locked (self)) { if (!secret_item_load_secret_sync (self, cancellable, error)) return FALSE; } return TRUE; } static void on_init_load_secret (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretItem *self = SECRET_ITEM (source); GError *error = NULL; if (!secret_item_load_secret_finish (self, result, &error)) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_boolean (task, TRUE); g_clear_object (&task); } static void item_ensure_for_flags_async (SecretItem *self, SecretItemFlags flags, GTask *task) { GCancellable *cancellable = g_task_get_cancellable (task); if (flags & SECRET_ITEM_LOAD_SECRET && !secret_item_get_locked (self)) secret_item_load_secret (self, cancellable, on_init_load_secret, g_object_ref (task)); else g_task_return_boolean (task, TRUE); } static gboolean secret_item_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { SecretItem *self; SecretService *service; GDBusProxy *proxy; if (!secret_item_initable_parent_iface->init (initable, cancellable, error)) return FALSE; proxy = G_DBUS_PROXY (initable); if (!_secret_util_have_cached_properties (proxy)) { g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "No such secret item at path: %s", g_dbus_proxy_get_object_path (proxy)); return FALSE; } self = SECRET_ITEM (initable); if (!self->pv->service) { service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error); if (service == NULL) return FALSE; else item_take_service (self, service); } return item_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error); } static void secret_item_initable_iface (GInitableIface *iface) { secret_item_initable_parent_iface = g_type_interface_peek_parent (iface); iface->init = secret_item_initable_init; } static void on_init_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretItem *self = SECRET_ITEM (g_task_get_source_object (task)); SecretService *service; GError *error = NULL; service = secret_service_get_finish (result, &error); if (error == NULL) { item_take_service (self, g_steal_pointer (&service)); item_ensure_for_flags_async (self, self->pv->init_flags, task); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } typedef struct { GAsyncReadyCallback callback; gpointer user_data; } InitBaseClosure; static void secret_item_async_initable_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); static void on_init_base (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *base_task = G_TASK (user_data); InitBaseClosure *base = g_task_get_task_data (base_task); GCancellable *cancellable = g_task_get_cancellable (base_task); GTask *task; SecretItem *self = SECRET_ITEM (source); GDBusProxy *proxy = G_DBUS_PROXY (self); GError *error = NULL; task = g_task_new (source, cancellable, base->callback, base->user_data); g_task_set_source_tag (task, secret_item_async_initable_init_async); g_clear_object (&base_task); if (!secret_item_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self), result, &error)) { g_task_return_error (task, g_steal_pointer (&error)); } else if (!_secret_util_have_cached_properties (proxy)) { g_task_return_new_error (task, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "No such secret item at path: %s", g_dbus_proxy_get_object_path (proxy)); } else if (self->pv->service == NULL) { secret_service_get (SECRET_SERVICE_NONE, cancellable, on_init_service, g_steal_pointer (&task)); } else { item_ensure_for_flags_async (self, self->pv->init_flags, task); } g_clear_object (&task); } static void secret_item_async_initable_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; InitBaseClosure *base; task = g_task_new (initable, cancellable, NULL, NULL); g_task_set_source_tag (task, secret_item_async_initable_init_async); base = g_new0 (InitBaseClosure, 1); base->callback = callback; base->user_data = user_data; g_task_set_task_data (task, base, g_free); secret_item_async_initable_parent_iface->init_async (initable, io_priority, cancellable, on_init_base, g_steal_pointer (&task)); g_clear_object (&task); } static gboolean secret_item_async_initable_init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, initable), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } static void secret_item_async_initable_iface (GAsyncInitableIface *iface) { secret_item_async_initable_parent_iface = g_type_interface_peek_parent (iface); iface->init_async = secret_item_async_initable_init_async; iface->init_finish = secret_item_async_initable_init_finish; } /** * secret_item_refresh: * @self: the collection * * Refresh the properties on this item. * * This fires off a request to refresh, and the properties will be updated * later. * * Calling this method is not normally necessary, as the secret service * will notify the client when properties change. */ void secret_item_refresh (SecretItem *self) { g_return_if_fail (SECRET_IS_ITEM (self)); _secret_util_get_properties (G_DBUS_PROXY (self), secret_item_refresh, NULL, NULL, NULL); } void _secret_item_set_cached_secret (SecretItem *self, SecretValue *value) { SecretValue *other = NULL; gboolean updated = FALSE; g_return_if_fail (SECRET_IS_ITEM (self)); if (value != NULL) secret_value_ref (value); g_mutex_lock (&self->pv->mutex); if (value != self->pv->value) { other = self->pv->value; self->pv->value = value; updated = TRUE; } else { other = value; } g_mutex_unlock (&self->pv->mutex); if (other != NULL) secret_value_unref (other); if (updated) g_object_notify (G_OBJECT (self), "flags"); } static void on_create_item (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretValue *value = g_task_get_task_data (task); SecretItem *item; GError *error = NULL; item = secret_item_new_for_dbus_path_finish (result, &error); if (item) { /* As a convenience mark down the SecretValue on the item */ _secret_item_set_cached_secret (item, value); g_task_return_pointer (task, item, g_object_unref); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } static void on_create_path (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GCancellable *cancellable = g_task_get_cancellable (task); SecretService *service = SECRET_SERVICE (source); GError *error = NULL; gchar *path; path = secret_service_create_item_dbus_path_finish (service, result, &error); if (error == NULL) { secret_item_new_for_dbus_path (service, path, SECRET_ITEM_NONE, cancellable, on_create_item, g_steal_pointer (&task)); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_free (path); g_clear_object (&task); } static GHashTable * item_properties_new (const gchar *label, const SecretSchema *schema, GHashTable *attributes) { const gchar *schema_name = NULL; GHashTable *properties; GVariant *value; if (schema != NULL) schema_name = schema->name; properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_variant_unref); value = g_variant_new_string (label); g_hash_table_insert (properties, SECRET_ITEM_INTERFACE ".Label", g_variant_ref_sink (value)); value = _secret_attributes_to_variant (attributes, schema_name); g_hash_table_insert (properties, SECRET_ITEM_INTERFACE ".Attributes", g_variant_ref_sink (value)); return properties; } /** * secret_item_create: * @collection: a secret collection to create this item in * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): attributes for the new item * @label: label for the new item * @value: secret value for the new item * @flags: flags for the creation of the new item * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Create a new item in the secret service. * * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret * service will search for an item matching the @attributes, and update that item * instead of creating a new one. * * This method may block indefinitely and should not be used in user interface * threads. The secret service may prompt the user. [method@Service.prompt] * will be used to handle any prompts that are required. */ void secret_item_create (SecretCollection *collection, const SecretSchema *schema, GHashTable *attributes, const gchar *label, SecretValue *value, SecretItemCreateFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretService *service = NULL; const gchar *collection_path; GTask *task; GHashTable *properties; g_return_if_fail (SECRET_IS_COLLECTION (collection)); g_return_if_fail (label != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (value != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; task = g_task_new (NULL, cancellable, callback, user_data); g_task_set_source_tag (task, secret_item_create); g_task_set_task_data (task, secret_value_ref (value), secret_value_unref); properties = item_properties_new (label, schema, attributes); g_object_get (collection, "service", &service, NULL); collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)); secret_service_create_item_dbus_path (service, collection_path, properties, value, flags, cancellable, on_create_path, g_steal_pointer (&task)); g_hash_table_unref (properties); g_object_unref (service); g_clear_object (&task); } /** * secret_item_create_finish: * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish operation to create a new item in the secret service. * * Returns: (transfer full): the new item, which should be unreferenced * with [method@GObject.Object.unref] */ SecretItem * secret_item_create_finish (GAsyncResult *result, GError **error) { SecretItem *retval; g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); retval = g_task_propagate_pointer (G_TASK (result), error); if (!retval) { _secret_util_strip_remote_error (error); return NULL; } return g_steal_pointer (&retval); } /** * secret_item_create_sync: * @collection: a secret collection to create this item in * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): attributes for the new item * @label: label for the new item * @value: secret value for the new item * @flags: flags for the creation of the new item * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Create a new item in the secret service. * * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret * service will search for an item matching the @attributes, and update that item * instead of creating a new one. * * This method may block indefinitely and should not be used in user interface * threads. The secret service may prompt the user. [method@Service.prompt] * will be used to handle any prompts that are required. * * Returns: (transfer full): the new item, which should be unreferenced * with [method@GObject.Object.unref] */ SecretItem * secret_item_create_sync (SecretCollection *collection, const SecretSchema *schema, GHashTable *attributes, const gchar *label, SecretValue *value, SecretItemCreateFlags flags, GCancellable *cancellable, GError **error) { SecretService *service = NULL; const gchar *collection_path; SecretItem *item = NULL; GHashTable *properties; gchar *path; g_return_val_if_fail (SECRET_IS_COLLECTION (collection), NULL); g_return_val_if_fail (label != NULL, NULL); g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (value != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return NULL; properties = item_properties_new (label, schema, attributes); g_object_get (collection, "service", &service, NULL); collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)); path = secret_service_create_item_dbus_path_sync (service, collection_path, properties, value, flags, cancellable, error); if (path != NULL) { item = secret_item_new_for_dbus_path_sync (service, path, SECRET_ITEM_NONE, cancellable, error); g_free (path); } g_hash_table_unref (properties); g_object_unref (service); return item; } static void on_item_deleted (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretService *service = SECRET_SERVICE (source); GError *error = NULL; if (!_secret_service_delete_path_finish (service, result, &error)) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_boolean (task, TRUE); g_clear_object (&task); } /** * secret_item_delete: * @self: an item * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Delete this item. * * This method returns immediately and completes asynchronously. The secret * service may prompt the user. [method@Service.prompt] will be used to handle * any prompts that show up. */ void secret_item_delete (SecretItem *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; const gchar *object_path; g_return_if_fail (SECRET_IS_ITEM (self)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self)); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_item_delete); _secret_service_delete_path (self->pv->service, object_path, TRUE, cancellable, on_item_deleted, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_item_delete_finish: * @self: an item * @result: asynchronous result passed to the callback * @error: location to place an error on failure * * Complete asynchronous operation to delete the secret item. * * Returns: whether the item was successfully deleted or not */ gboolean secret_item_delete_finish (SecretItem *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_task_is_valid (result, self), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_item_delete_sync: * @self: an item * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Delete this secret item. * * This method may block indefinitely and should not be used in user * interface threads. The secret service may prompt the user. * [method@Service.prompt] will be used to handle any prompts that show up. * * Returns: whether the item was successfully deleted or not */ gboolean secret_item_delete_sync (SecretItem *self, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_item_delete (self, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_item_delete_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } /** * secret_item_get_flags: (attributes org.gtk.Method.get_property=flags) * @self: the secret item proxy * * Get the flags representing what features of the #SecretItem proxy * have been initialized. * * Use [method@Item.load_secret] to initialize further features * and change the flags. * * Returns: the flags for features initialized */ SecretItemFlags secret_item_get_flags (SecretItem *self) { SecretServiceFlags flags = 0; g_return_val_if_fail (SECRET_IS_ITEM (self), SECRET_ITEM_NONE); g_mutex_lock (&self->pv->mutex); if (self->pv->value) flags |= SECRET_ITEM_LOAD_SECRET; g_mutex_unlock (&self->pv->mutex); return flags; } /** * secret_item_get_service: (attributes org.gtk.Method.get_property=service) * @self: an item * * Get the Secret Service object that this item was created with. * * Returns: (transfer none): the Secret Service object */ SecretService * secret_item_get_service (SecretItem *self) { g_return_val_if_fail (SECRET_IS_ITEM (self), NULL); return self->pv->service; } /** * secret_item_get_secret: * @self: an item * * Get the secret value of this item. * * If this item is locked or the secret has not yet been loaded then this will * return %NULL. * * To load the secret call the [method@Item.load_secret] method. * * Returns: (transfer full) (nullable): the secret value which should be * released with [method@Value.unref], or %NULL */ SecretValue * secret_item_get_secret (SecretItem *self) { SecretValue *value = NULL; g_return_val_if_fail (SECRET_IS_ITEM (self), NULL); g_mutex_lock (&self->pv->mutex); if (self->pv->value) value = secret_value_ref (self->pv->value); g_mutex_unlock (&self->pv->mutex); return value; } static void on_item_load_secret (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretItem *self = SECRET_ITEM (g_task_get_source_object (task)); SecretSession *session; GError *error = NULL; SecretValue *value; GVariant *retval; GVariant *child; retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); if (error == NULL) { child = g_variant_get_child_value (retval, 0); g_variant_unref (retval); session = _secret_service_get_session (self->pv->service); value = _secret_session_decode_secret (session, child); g_variant_unref (child); if (value == NULL) { g_set_error (&error, SECRET_ERROR, SECRET_ERROR_PROTOCOL, _("Received invalid secret from the secret storage")); } else { _secret_item_set_cached_secret (self, value); secret_value_unref (value); } } if (error == NULL) g_task_return_boolean (task, TRUE); else g_task_return_error (task, g_steal_pointer (&error)); g_clear_object (&task); } static void on_load_ensure_session (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretItem *self = SECRET_ITEM (g_task_get_source_object (task)); GCancellable *cancellable = g_task_get_cancellable (task); const gchar *session_path; GError *error = NULL; secret_service_ensure_session_finish (self->pv->service, result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else { session_path = secret_service_get_session_dbus_path (self->pv->service); g_assert (session_path != NULL && session_path[0] != '\0'); g_dbus_proxy_call (G_DBUS_PROXY (self), "GetSecret", g_variant_new ("(o)", session_path), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_item_load_secret, g_steal_pointer (&task)); } g_clear_object (&task); } /** * secret_item_load_secret: * @self: an item proxy * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Load the secret value of this item. * * Each item has a single secret which might be a password or some * other secret binary value. * * This function will fail if the secret item is locked. * * This function returns immediately and completes asynchronously. */ void secret_item_load_secret (SecretItem *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; g_return_if_fail (SECRET_IS_ITEM (self)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_item_load_secret); secret_service_ensure_session (self->pv->service, cancellable, on_load_ensure_session, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_item_load_secret_finish: * @self: an item proxy * @result: asynchronous result passed to callback * @error: location to place error on failure * * Complete asynchronous operation to load the secret value of this item. * * The newly loaded secret value can be accessed by calling * [method@Item.get_secret]. * * Returns: whether the secret item successfully loaded or not */ gboolean secret_item_load_secret_finish (SecretItem *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, self), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_item_load_secret_sync: * @self: an item * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Load the secret value of this item. * * Each item has a single secret which might be a password or some * other secret binary value. * * This function may block indefinitely. Use the asynchronous version * in user interface threads. * * Returns: whether the secret item successfully loaded or not */ gboolean secret_item_load_secret_sync (SecretItem *self, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean result; g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_item_load_secret (self, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); result = secret_item_load_secret_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return result; } static void on_retrieve_load (GObject *source_object, GAsyncResult *res, gpointer user_data) { SecretItem *self = SECRET_ITEM (source_object); GTask *task = G_TASK (user_data); GError *error = NULL; if (secret_item_load_secret_finish (self, res, &error)) { g_task_return_pointer (task, secret_item_get_secret (self), secret_value_unref); g_object_unref (task); } else { g_task_return_error (task, error); g_object_unref (task); } } static void secret_item_retrieve_secret (SecretRetrievable *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task = g_task_new (self, cancellable, callback, user_data); secret_item_load_secret (SECRET_ITEM (self), cancellable, on_retrieve_load, task); } static SecretValue * secret_item_retrieve_secret_finish (SecretRetrievable *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, self), NULL); return g_task_propagate_pointer (G_TASK (result), error); } static void secret_item_retrievable_iface (SecretRetrievableInterface *iface) { secret_item_retrievable_parent_iface = g_type_interface_peek_parent (iface); iface->retrieve_secret = secret_item_retrieve_secret; iface->retrieve_secret_finish = secret_item_retrieve_secret_finish; } typedef struct { SecretService *service; GVariant *in; GHashTable *items; } LoadsClosure; static void loads_closure_free (gpointer data) { LoadsClosure *loads = data; if (loads->in) g_variant_unref (loads->in); if (loads->service) g_object_unref (loads->service); g_hash_table_destroy (loads->items); g_free (loads); } static void on_get_secrets_complete (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); LoadsClosure *loads = g_task_get_task_data (task); GHashTable *with_paths; GError *error = NULL; GHashTableIter iter; const gchar *path; SecretValue *value; SecretItem *item; GVariant *retval; retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); if (retval != NULL) { with_paths = _secret_service_decode_get_secrets_all (loads->service, retval); g_return_if_fail (with_paths != NULL); g_hash_table_iter_init (&iter, with_paths); while (g_hash_table_iter_next (&iter, (gpointer *)&path, (gpointer *)&value)) { item = g_hash_table_lookup (loads->items, path); if (item != NULL) _secret_item_set_cached_secret (item, value); } g_hash_table_unref (with_paths); g_variant_unref (retval); } if (error != NULL) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_boolean (task, TRUE); g_clear_object (&task); } static void on_loads_secrets_session (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); LoadsClosure *loads = g_task_get_task_data (task); GError *error = NULL; const gchar *session; secret_service_ensure_session_finish (SECRET_SERVICE (source), result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); g_clear_object (&task); return; } session = secret_service_get_session_dbus_path (SECRET_SERVICE (source)); g_dbus_proxy_call (G_DBUS_PROXY (source), "GetSecrets", g_variant_new ("(@aoo)", loads->in, session), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, g_task_get_cancellable (task), on_get_secrets_complete, g_object_ref (task)); g_clear_object (&task); } /** * secret_item_load_secrets: * @items: (element-type Secret.Item): the items to retrieve secrets for * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Load the secret values for a secret item stored in the service. * * The @items must all have the same [property@Item:service] property. * * This function returns immediately and completes asynchronously. */ void secret_item_load_secrets (GList *items, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; LoadsClosure *loads; GPtrArray *paths; const gchar *path; GList *l; g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); for (l = items; l != NULL; l = g_list_next (l)) g_return_if_fail (SECRET_IS_ITEM (l->data)); task = g_task_new (NULL, cancellable, callback, user_data); g_task_set_source_tag (task, secret_item_load_secrets); loads = g_new0 (LoadsClosure, 1); loads->items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); paths = g_ptr_array_new (); for (l = items; l != NULL; l = g_list_next (l)) { if (secret_item_get_locked (l->data)) continue; if (loads->service == NULL) { loads->service = secret_item_get_service (l->data); if (loads->service) g_object_ref (loads->service); } path = g_dbus_proxy_get_object_path (l->data); g_hash_table_insert (loads->items, g_strdup (path), g_object_ref (l->data)); g_ptr_array_add (paths, (gpointer)path); } loads->in = g_variant_new_objv ((const gchar * const *)paths->pdata, paths->len); g_variant_ref_sink (loads->in); g_ptr_array_free (paths, TRUE); g_task_set_task_data (task, loads, loads_closure_free); if (loads->service) { secret_service_ensure_session (loads->service, cancellable, on_loads_secrets_session, g_object_ref (task)); } else { g_task_return_boolean (task, TRUE); } g_clear_object (&task); } /** * secret_item_load_secrets_finish: * @result: asynchronous result passed to callback * @error: location to place an error on failure * * Complete asynchronous operation to load the secret values for * secret items stored in the service. * * Items that are locked will not have their secrets loaded. * * Returns: whether the operation succeeded or not */ gboolean secret_item_load_secrets_finish (GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_item_load_secrets_sync: * @items: (element-type Secret.Item): the items to retrieve secrets for * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Load the secret values for a secret item stored in the service. * * The @items must all have the same [property@Item:service] property. * * This method may block indefinitely and should not be used in user interface * threads. * * Items that are locked will not have their secrets loaded. * * Returns: whether the operation succeeded or not */ gboolean secret_item_load_secrets_sync (GList *items, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; GList *l; for (l = items; l != NULL; l = g_list_next (l)) g_return_val_if_fail (SECRET_IS_ITEM (l->data), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_item_load_secrets (items, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_item_load_secrets_finish (sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } static void on_item_set_secret (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretItem *self = SECRET_ITEM (g_task_get_source_object (task)); SecretValue *value = g_task_get_task_data (task); GError *error = NULL; GVariant *retval; retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); if (error) { g_task_return_error (task, g_steal_pointer (&error)); g_clear_object (&task); return; } _secret_item_set_cached_secret (self, value); g_clear_pointer (&retval, g_variant_unref); g_task_return_boolean (task, TRUE); g_clear_object (&task); } static void on_set_ensure_session (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretItem *self = SECRET_ITEM (g_task_get_source_object (task)); SecretValue *value = g_task_get_task_data (task); SecretSession *session; GVariant *encoded; GError *error = NULL; secret_service_ensure_session_finish (self->pv->service, result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); g_clear_object (&task); return; } session = _secret_service_get_session (self->pv->service); encoded = _secret_session_encode_secret (session, value); g_dbus_proxy_call (G_DBUS_PROXY (self), "SetSecret", g_variant_new ("(@(oayays))", encoded), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, g_task_get_cancellable (task), on_item_set_secret, g_object_ref (task)); g_clear_object (&task); } /** * secret_item_set_secret: * @self: an item * @value: a new secret value * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Set the secret value of this item. * * Each item has a single secret which might be a password or some * other secret binary value. * * This function returns immediately and completes asynchronously. */ void secret_item_set_secret (SecretItem *self, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task = NULL; g_return_if_fail (SECRET_IS_ITEM (self)); g_return_if_fail (value != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_item_set_secret); g_task_set_task_data (task, secret_value_ref (value), secret_value_unref); secret_service_ensure_session (self->pv->service, cancellable, on_set_ensure_session, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_item_set_secret_finish: * @self: an item * @result: asynchronous result passed to callback * @error: location to place error on failure * * Complete asynchronous operation to set the secret value of this item. * * Returns: whether the change was successful or not */ gboolean secret_item_set_secret_finish (SecretItem *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, self), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_item_set_secret_sync: * @self: an item * @value: a new secret value * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Set the secret value of this item. * * Each item has a single secret which might be a password or some * other secret binary value. * * This function may block indefinitely. Use the asynchronous version * in user interface threads. * * Returns: whether the change was successful or not */ gboolean secret_item_set_secret_sync (SecretItem *self, SecretValue *value, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_item_set_secret (self, value, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_item_set_secret_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } /** * secret_item_get_schema_name: * @self: an item * * Gets the name of the schema that this item was stored with. This is also * available at the `xdg:schema` attribute. * * Returns: (nullable) (transfer full): the schema name */ gchar * secret_item_get_schema_name (SecretItem *self) { gchar *schema_name = NULL; GVariant *variant; g_return_val_if_fail (SECRET_IS_ITEM (self), NULL); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Attributes"); g_return_val_if_fail (variant != NULL, NULL); g_variant_lookup (variant, "xdg:schema", "s", &schema_name); g_variant_unref (variant); return schema_name; } /** * secret_item_get_attributes: * @self: an item * * Set the attributes of this item. * * The @attributes are a mapping of string keys to string values. * Attributes are used to search for items. Attributes are not stored * or transferred securely by the secret service. * * Do not modify the attributes returned by this method. Use * [method@Item.set_attributes] instead. * * Returns: (transfer full) (element-type utf8 utf8): a new reference * to the attributes, which should not be modified, and * released with [func@GLib.HashTable.unref] */ GHashTable * secret_item_get_attributes (SecretItem *self) { GHashTable *attributes; GVariant *variant; g_return_val_if_fail (SECRET_IS_ITEM (self), NULL); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Attributes"); g_return_val_if_fail (variant != NULL, NULL); attributes = _secret_attributes_for_variant (variant); g_variant_unref (variant); return attributes; } /** * secret_item_set_attributes: * @self: an item * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): a new set of attributes * @cancellable: (nullable): optional cancellation object * @callback: called when the asynchronous operation completes * @user_data: data to pass to the callback * * Set the attributes of this item. * * The @attributes are a mapping of string keys to string values. * Attributes are used to search for items. Attributes are not stored * or transferred securely by the secret service. * * This function returns immediately and completes asynchronously. */ void secret_item_set_attributes (SecretItem *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { const gchar *schema_name = NULL; g_return_if_fail (SECRET_IS_ITEM (self)); g_return_if_fail (attributes != NULL); if (schema != NULL) { if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; /* Warnings raised already */ schema_name = schema->name; } _secret_util_set_property (G_DBUS_PROXY (self), "Attributes", _secret_attributes_to_variant (attributes, schema_name), secret_item_set_attributes, cancellable, callback, user_data); } /** * secret_item_set_attributes_finish: * @self: an item * @result: asynchronous result passed to the callback * @error: location to place error on failure * * Complete operation to set the attributes of this item. * * Returns: whether the change was successful or not */ gboolean secret_item_set_attributes_finish (SecretItem *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE); return _secret_util_set_property_finish (G_DBUS_PROXY (self), secret_item_set_attributes, result, error); } /** * secret_item_set_attributes_sync: * @self: an item * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): a new set of attributes * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Set the attributes of this item. * * The @attributes are a mapping of string keys to string values. * Attributes are used to search for items. Attributes are not stored * or transferred securely by the secret service. * * This function may block indefinitely. Use the asynchronous version * in user interface threads. * * Returns: whether the change was successful or not */ gboolean secret_item_set_attributes_sync (SecretItem *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error) { const gchar *schema_name = NULL; g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE); g_return_val_if_fail (attributes != NULL, FALSE); if (schema != NULL) { if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return FALSE; /* Warnings raised already */ schema_name = schema->name; } return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Attributes", _secret_attributes_to_variant (attributes, schema_name), cancellable, error); } /** * secret_item_get_label: * @self: an item * * Get the label of this item. * * Returns: (transfer full): the label, which should be freed with [func@GLib.free] */ gchar * secret_item_get_label (SecretItem *self) { GVariant *variant; gchar *label; g_return_val_if_fail (SECRET_IS_ITEM (self), NULL); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Label"); g_return_val_if_fail (variant != NULL, NULL); label = g_variant_dup_string (variant, NULL); g_variant_unref (variant); return label; } /** * secret_item_set_label: * @self: an item * @label: a new label * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Set the label of this item. * * This function returns immediately and completes asynchronously. */ void secret_item_set_label (SecretItem *self, const gchar *label, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_ITEM (self)); g_return_if_fail (label != NULL); _secret_util_set_property (G_DBUS_PROXY (self), "Label", g_variant_new_string (label), secret_item_set_label, cancellable, callback, user_data); } /** * secret_item_set_label_finish: * @self: an item * @result: asynchronous result passed to callback * @error: location to place error on failure * * Complete asynchronous operation to set the label of this collection. * * Returns: whether the change was successful or not */ gboolean secret_item_set_label_finish (SecretItem *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE); return _secret_util_set_property_finish (G_DBUS_PROXY (self), secret_item_set_label, result, error); } /** * secret_item_set_label_sync: * @self: an item * @label: a new label * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Set the label of this item. * * This function may block indefinitely. Use the asynchronous version * in user interface threads. * * Returns: whether the change was successful or not */ gboolean secret_item_set_label_sync (SecretItem *self, const gchar *label, GCancellable *cancellable, GError **error) { g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE); g_return_val_if_fail (label != NULL, FALSE); return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Label", g_variant_new_string (label), cancellable, error); } /** * secret_item_get_locked: * @self: an item * * Get whether the item is locked or not. * * Depending on the secret service an item may not be able to be locked * independently from the collection that it is in. * * Returns: whether the item is locked or not */ gboolean secret_item_get_locked (SecretItem *self) { GVariant *variant; gboolean locked; g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Locked"); g_return_val_if_fail (variant != NULL, TRUE); locked = g_variant_get_boolean (variant); g_variant_unref (variant); return locked; } /** * secret_item_get_created: * @self: an item * * Get the created date and time of the item. * * The return value is the number of seconds since the unix epoch, January 1st * 1970. * * Returns: the created date and time */ guint64 secret_item_get_created (SecretItem *self) { GVariant *variant; guint64 created; g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Created"); g_return_val_if_fail (variant != NULL, 0); created = g_variant_get_uint64 (variant); g_variant_unref (variant); return created; } /** * secret_item_get_modified: * @self: an item * * Get the modified date and time of the item. * * The return value is the number of seconds since the unix epoch, January 1st * 1970. * * Returns: the modified date and time */ guint64 secret_item_get_modified (SecretItem *self) { GVariant *variant; guint64 modified; g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE); variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Modified"); g_return_val_if_fail (variant != NULL, 0); modified = g_variant_get_uint64 (variant); g_variant_unref (variant); return modified; } 07070100000068000081A400000000000000000000000167D9F0D9000026B7000000000000000000000000000000000000002900000000libsecret-0.21.7/libsecret/secret-item.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_ITEM_H__ #define __SECRET_ITEM_H__ #include #include "secret-collection.h" #include "secret-service.h" #include "secret-value.h" G_BEGIN_DECLS typedef enum { SECRET_ITEM_NONE, SECRET_ITEM_LOAD_SECRET = 1 << 1 } SecretItemFlags; typedef enum { SECRET_ITEM_CREATE_NONE = 0, SECRET_ITEM_CREATE_REPLACE = 1 << 1 } SecretItemCreateFlags; #define SECRET_TYPE_ITEM (secret_item_get_type ()) #define SECRET_ITEM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), SECRET_TYPE_ITEM, SecretItem)) #define SECRET_ITEM_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), SECRET_TYPE_ITEM, SecretItemClass)) #define SECRET_IS_ITEM(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), SECRET_TYPE_ITEM)) #define SECRET_IS_ITEM_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), SECRET_TYPE_ITEM)) #define SECRET_ITEM_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), SECRET_TYPE_ITEM, SecretItemClass)) typedef struct _SecretItemClass SecretItemClass; typedef struct _SecretItemPrivate SecretItemPrivate; struct _SecretItem { GDBusProxy parent_instance; /*< private >*/ SecretItemPrivate *pv; }; struct _SecretItemClass { GDBusProxyClass parent_class; /*< private >*/ gpointer padding[4]; }; GType secret_item_get_type (void) G_GNUC_CONST; void secret_item_refresh (SecretItem *self); void secret_item_create (SecretCollection *collection, const SecretSchema *schema, GHashTable *attributes, const gchar *label, SecretValue *value, SecretItemCreateFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretItem * secret_item_create_finish (GAsyncResult *result, GError **error); SecretItem * secret_item_create_sync (SecretCollection *collection, const SecretSchema *schema, GHashTable *attributes, const gchar *label, SecretValue *value, SecretItemCreateFlags flags, GCancellable *cancellable, GError **error); void secret_item_delete (SecretItem *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_item_delete_finish (SecretItem *self, GAsyncResult *result, GError **error); gboolean secret_item_delete_sync (SecretItem *self, GCancellable *cancellable, GError **error); SecretItemFlags secret_item_get_flags (SecretItem *self); SecretService * secret_item_get_service (SecretItem *self); SecretValue * secret_item_get_secret (SecretItem *self); void secret_item_load_secret (SecretItem *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_item_load_secret_finish (SecretItem *self, GAsyncResult *result, GError **error); gboolean secret_item_load_secret_sync (SecretItem *self, GCancellable *cancellable, GError **error); void secret_item_load_secrets (GList *items, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_item_load_secrets_finish (GAsyncResult *result, GError **error); gboolean secret_item_load_secrets_sync (GList *items, GCancellable *cancellable, GError **error); void secret_item_set_secret (SecretItem *self, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_item_set_secret_finish (SecretItem *self, GAsyncResult *result, GError **error); gboolean secret_item_set_secret_sync (SecretItem *self, SecretValue *value, GCancellable *cancellable, GError **error); gchar * secret_item_get_schema_name (SecretItem *self); GHashTable* secret_item_get_attributes (SecretItem *self); void secret_item_set_attributes (SecretItem *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_item_set_attributes_finish (SecretItem *self, GAsyncResult *result, GError **error); gboolean secret_item_set_attributes_sync (SecretItem *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); gchar * secret_item_get_label (SecretItem *self); void secret_item_set_label (SecretItem *self, const gchar *label, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_item_set_label_finish (SecretItem *self, GAsyncResult *result, GError **error); gboolean secret_item_set_label_sync (SecretItem *self, const gchar *label, GCancellable *cancellable, GError **error); gboolean secret_item_get_locked (SecretItem *self); guint64 secret_item_get_created (SecretItem *self); guint64 secret_item_get_modified (SecretItem *self); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecretItem, g_object_unref) G_END_DECLS #endif /* __SECRET_ITEM_H___ */ 07070100000069000081A400000000000000000000000167D9F0D90000FF5C000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/secret-methods.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-collection.h" #include "secret-dbus-generated.h" #include "secret-item.h" #include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "secret-types.h" #include "secret-value.h" #include /** * SecretSearchFlags: * @SECRET_SEARCH_NONE: no flags * @SECRET_SEARCH_ALL: all the items matching the search will be returned, instead of just the first one * @SECRET_SEARCH_UNLOCK: unlock locked items while searching * @SECRET_SEARCH_LOAD_SECRETS: while searching load secrets for items that are not locked * * Various flags to be used with [method@Service.search] and [method@Service.search_sync]. */ typedef struct { SecretService *service; GHashTable *items; gchar **unlocked; gchar **locked; guint loading; SecretSearchFlags flags; GVariant *attributes; } SearchClosure; static void search_closure_free (gpointer data) { SearchClosure *closure = data; g_clear_object (&closure->service); g_hash_table_unref (closure->items); g_variant_unref (closure->attributes); g_strfreev (closure->unlocked); g_strfreev (closure->locked); g_free (closure); } static void search_closure_take_item (SearchClosure *closure, SecretItem *item) { const gchar *path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)); g_hash_table_insert (closure->items, (gpointer)path, item); } static GList * search_closure_build_items (SearchClosure *closure, gchar **paths) { GList *results = NULL; SecretItem *item; guint i; for (i = 0; paths[i]; i++) { item = g_hash_table_lookup (closure->items, paths[i]); if (item != NULL) results = g_list_prepend (results, g_object_ref (item)); } return g_list_reverse (results); } static void on_search_secrets (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); /* Note that we ignore any unlock failure */ secret_item_load_secrets_finish (result, NULL); g_task_return_boolean (task, TRUE); g_clear_object (&task); } static void secret_search_load_or_complete (GTask *task, SearchClosure *search) { GCancellable *cancellable = g_task_get_cancellable (task); GList *items; /* If loading secrets ... locked items automatically ignored */ if (search->flags & SECRET_SEARCH_LOAD_SECRETS) { items = g_hash_table_get_values (search->items); secret_item_load_secrets (items, cancellable, on_search_secrets, g_object_ref (task)); g_list_free (items); /* No additional options, just complete */ } else { g_task_return_boolean (task, TRUE); } } static void on_search_loaded (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SearchClosure *closure = g_task_get_task_data (task); GError *error = NULL; SecretItem *item; closure->loading--; item = secret_item_new_for_dbus_path_finish (result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); g_clear_object (&task); return; } if (item != NULL) search_closure_take_item (closure, item); /* We're done loading, lets go to the next step */ if (closure->loading == 0) secret_search_load_or_complete (task, closure); g_clear_object (&task); } static void search_load_item_async (SecretService *self, GTask *task, SearchClosure *closure, const gchar *path) { GCancellable *cancellable = g_task_get_cancellable (task); SecretItem *item; item = _secret_service_find_item_instance (self, path); if (item == NULL) { secret_item_new_for_dbus_path (self, path, SECRET_ITEM_NONE, cancellable, on_search_loaded, g_object_ref (task)); closure->loading++; } else { search_closure_take_item (closure, item); } } static void load_items (SearchClosure *closure, GTask *task) { SecretService *self = closure->service; gint want = 1; gint count = 0; gint i; if (closure->flags & SECRET_SEARCH_ALL) want = G_MAXINT; for (i = 0; count < want && closure->unlocked[i] != NULL; i++, count++) search_load_item_async (self, task, closure, closure->unlocked[i]); for (i = 0; count < want && closure->locked[i] != NULL; i++, count++) search_load_item_async (self, task, closure, closure->locked[i]); /* No items loading, complete operation now */ if (closure->loading == 0) secret_search_load_or_complete (task, closure); } static void on_unlock_paths (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SearchClosure *closure = g_task_get_task_data (task); SecretService *self = closure->service; /* Note that we ignore any unlock failure */ secret_service_unlock_dbus_paths_finish (self, result, NULL, NULL); load_items (closure, task); g_clear_object (&task); } static void on_search_paths (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SearchClosure *closure = g_task_get_task_data (task); SecretService *self = closure->service; GError *error = NULL; secret_service_search_for_dbus_paths_finish (self, result, &closure->unlocked, &closure->locked, &error); if (error == NULL) { /* If unlocking then unlock all the locked items */ if (closure->flags & SECRET_SEARCH_UNLOCK) { GCancellable *cancellable = g_task_get_cancellable (task); const gchar **const_locked = (const gchar**) closure->locked; secret_service_unlock_dbus_paths (self, const_locked, cancellable, on_unlock_paths, g_steal_pointer (&task)); } else { load_items (closure, task); } } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } static void on_search_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SearchClosure *search = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; search->service = secret_service_get_finish (result, &error); if (error == NULL) { _secret_service_search_for_paths_variant (search->service, search->attributes, cancellable, on_search_paths, g_steal_pointer (&task)); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } /** * secret_service_search: * @service: (nullable): the secret service * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @flags: search option flags * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Search for items matching the @attributes. * * All collections are searched. The @attributes should be a table of string * keys and string values. * * If @service is %NULL, then [func@Service.get] will be called to get * the default [class@Service] proxy. * * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the * search will be returned. Otherwise only the first item will be returned. * This is almost always the unlocked item that was most recently stored. * * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked * if necessary. In either case, locked and unlocked items will match the * search and be returned. If the unlock fails, the search does not fail. * * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items will have * their secret values loaded and available via [method@Item.get_secret]. * * This function returns immediately and completes asynchronously. */ void secret_service_search (SecretService *service, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; SearchClosure *closure; const gchar *schema_name = NULL; g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) schema_name = schema->name; task = g_task_new (service, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_search); closure = g_new0 (SearchClosure, 1); closure->items = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); closure->flags = flags; closure->attributes = _secret_attributes_to_variant (attributes, schema_name); g_variant_ref_sink (closure->attributes); g_task_set_task_data (task, closure, search_closure_free); if (service) { closure->service = g_object_ref (service); _secret_service_search_for_paths_variant (closure->service, closure->attributes, cancellable, on_search_paths, g_steal_pointer (&task)); } else { secret_service_get (SECRET_SERVICE_NONE, cancellable, on_search_service, g_steal_pointer (&task)); } g_clear_object (&task); } /** * secret_service_search_finish: * @service: (nullable): the secret service * @result: asynchronous result passed to callback * @error: location to place error on failure * * Complete asynchronous operation to search for items. * * Returns: (transfer full) (element-type Secret.Item): * a list of items that matched the search */ GList * secret_service_search_finish (SecretService *service, GAsyncResult *result, GError **error) { SearchClosure *closure; GList *items = NULL; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (g_task_is_valid (result, service), NULL); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return NULL; } closure = g_task_get_task_data (G_TASK (result)); if (closure->unlocked) items = search_closure_build_items (closure, closure->unlocked); if (closure->locked) items = g_list_concat (items, search_closure_build_items (closure, closure->locked)); return items; } static gboolean service_load_items_sync (SecretService *service, GCancellable *cancellable, gchar **paths, GList **items, gint want, gint *have, GError **error) { SecretItem *item; guint i; for (i = 0; *have < want && paths[i] != NULL; i++) { item = _secret_service_find_item_instance (service, paths[i]); if (item == NULL) item = secret_item_new_for_dbus_path_sync (service, paths[i], SECRET_ITEM_NONE, cancellable, error); if (item == NULL) { return FALSE; } else { *items = g_list_prepend (*items, item); (*have)++; } } return TRUE; } /** * secret_service_search_sync: * @service: (nullable): the secret service * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @flags: search option flags * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Search for items matching the @attributes. * * All collections are searched. The @attributes should be a table of string * keys and string values. * * If @service is %NULL, then [func@Service.get_sync] will be called to get * the default [class@Service] proxy. * * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the * search will be returned. Otherwise only the first item will be returned. * This is almost always the unlocked item that was most recently stored. * * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked * if necessary. In either case, locked and unlocked items will match the * search and be returned. If the unlock fails, the search does not fail. * * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items' secret * values will be loaded for any unlocked items. Loaded item secret values * are available via [method@Item.get_secret]. If the load of a secret values * fail, then the * * This function may block indefinitely. Use the asynchronous version * in user interface threads. * * Returns: (transfer full) (element-type Secret.Item): * a list of items that matched the search */ GList * secret_service_search_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GError **error) { gchar **unlocked_paths = NULL; gchar **locked_paths = NULL; GList *items = NULL; GList *locked = NULL; GList *unlocked = NULL; gboolean ret; gint want; gint have; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return NULL; if (service == NULL) { service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error); if (service == NULL) return NULL; } else { g_object_ref (service); } if (!secret_service_search_for_dbus_paths_sync (service, schema, attributes, cancellable, &unlocked_paths, &locked_paths, error)) { g_object_unref (service); return NULL; } if (flags & SECRET_SEARCH_UNLOCK) secret_service_unlock_dbus_paths_sync (service, (const gchar**) locked_paths, cancellable, NULL, NULL); ret = TRUE; want = 1; if (flags & SECRET_SEARCH_ALL) want = G_MAXINT; have = 0; /* Remember, we're adding to the list backwards */ if (unlocked_paths) { ret = service_load_items_sync (service, cancellable, unlocked_paths, &unlocked, want, &have, error); } if (ret && locked_paths) { ret = service_load_items_sync (service, cancellable, locked_paths, &locked, want, &have, error); } g_strfreev (unlocked_paths); g_strfreev (locked_paths); if (!ret) { g_list_free_full (unlocked, g_object_unref); g_list_free_full (locked, g_object_unref); g_object_unref (service); return NULL; } /* The lists are backwards at this point ... */ items = g_list_concat (items, g_list_copy (locked)); items = g_list_concat (items, g_list_copy (unlocked)); items = g_list_reverse (items); if (flags & SECRET_SEARCH_LOAD_SECRETS) secret_item_load_secrets_sync (items, NULL, NULL); g_list_free (locked); g_list_free (unlocked); g_object_unref (service); return items; } SecretValue * _secret_service_decode_get_secrets_first (SecretService *self, GVariant *out) { SecretSession *session; SecretValue *value = NULL; GVariantIter *iter; GVariant *variant; const gchar *path; g_variant_get (out, "(a{o(oayays)})", &iter); while (g_variant_iter_next (iter, "{&o@(oayays)}", &path, &variant)) { session = _secret_service_get_session (self); value = _secret_session_decode_secret (session, variant); g_variant_unref (variant); break; } g_variant_iter_free (iter); return value; } GHashTable * _secret_service_decode_get_secrets_all (SecretService *self, GVariant *out) { SecretSession *session; GVariantIter *iter; GVariant *variant; GHashTable *values; SecretValue *value; gchar *path; session = _secret_service_get_session (self); values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, secret_value_unref); g_variant_get (out, "(a{o(oayays)})", &iter); while (g_variant_iter_loop (iter, "{o@(oayays)}", &path, &variant)) { value = _secret_session_decode_secret (session, variant); if (value && path) g_hash_table_insert (values, g_strdup (path), value); } g_variant_iter_free (iter); return values; } typedef struct { GPtrArray *paths; GHashTable *objects; gchar **xlocked; gboolean locking; } XlockClosure; static void xlock_closure_free (gpointer data) { XlockClosure *closure = data; g_ptr_array_free (closure->paths, TRUE); g_strfreev (closure->xlocked); g_hash_table_unref (closure->objects); g_free (closure); } static void on_xlock_paths (GObject *source, GAsyncResult *result, gpointer user_data) { SecretService *service = SECRET_SERVICE (source); GTask *task = G_TASK (user_data); XlockClosure *xlock = g_task_get_task_data (task); GVariant *lockval; GDBusProxy *object; GError *error = NULL; gint count; gint i; count = _secret_service_xlock_paths_finish (service, result, &xlock->xlocked, &error); if (error == NULL) { /* * After a lock or unlock we want the Locked property to immediately * reflect the new state, and not have to wait for a PropertiesChanged * signal to be processed later. */ lockval = g_variant_ref_sink (g_variant_new_boolean (xlock->locking)); for (i = 0; xlock->xlocked[i] != NULL; i++) { object = g_hash_table_lookup (xlock->objects, xlock->xlocked[i]); if (object != NULL) g_dbus_proxy_set_cached_property (object, "Locked", lockval); } g_variant_unref (lockval); g_task_return_int (task, count); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } static void on_xlock_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); XlockClosure *xlock = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; SecretService *service; service = secret_service_get_finish (result, &error); if (error == NULL) { _secret_service_xlock_paths_async (service, xlock->locking ? "Lock" : "Unlock", (const gchar **)xlock->paths->pdata, cancellable, on_xlock_paths, g_steal_pointer (&task)); g_object_unref (service); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } static void service_xlock_async (SecretService *service, gboolean locking, GList *objects, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; XlockClosure *xlock; const gchar *path; GList *l; task = g_task_new (service, cancellable, callback, user_data); g_task_set_source_tag (task, service_xlock_async); xlock = g_new0 (XlockClosure, 1); xlock->objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); xlock->locking = locking; xlock->paths = g_ptr_array_new (); for (l = objects; l != NULL; l = g_list_next (l)) { path = g_dbus_proxy_get_object_path (l->data); g_ptr_array_add (xlock->paths, (gpointer)path); g_hash_table_insert (xlock->objects, g_strdup (path), g_object_ref (l->data)); } g_ptr_array_add (xlock->paths, NULL); g_task_set_task_data (task, xlock, xlock_closure_free); if (service == NULL) { secret_service_get (SECRET_SERVICE_NONE, cancellable, on_xlock_service, g_steal_pointer (&task)); } else { _secret_service_xlock_paths_async (service, xlock->locking ? "Lock" : "Unlock", (const gchar **)xlock->paths->pdata, cancellable, on_xlock_paths, g_steal_pointer (&task)); } g_clear_object (&task); } static gint service_xlock_finish (SecretService *service, GAsyncResult *result, GList **xlocked, GError **error) { XlockClosure *xlock; GDBusProxy *object; gint count; gint i; g_return_val_if_fail (g_task_is_valid (result, service), -1); count = g_task_propagate_int (G_TASK (result), error); if (count == -1) { _secret_util_strip_remote_error (error); return -1; } xlock = g_task_get_task_data (G_TASK (result)); if (xlocked) { *xlocked = NULL; for (i = 0; xlock->xlocked[i] != NULL; i++) { object = g_hash_table_lookup (xlock->objects, xlock->xlocked[i]); if (object != NULL) *xlocked = g_list_prepend (*xlocked, g_object_ref (object)); } } return count; } /** * secret_service_lock: * @service: (nullable): the secret service * @objects: (element-type Gio.DBusProxy): the items or collections to lock * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Lock items or collections in the secret service. * * The secret service may not be able to lock items individually, and may * lock an entire collection instead. * * If @service is %NULL, then [func@Service.get] will be called to get * the default [class@Service] proxy. * * This method returns immediately and completes asynchronously. The secret * service may prompt the user. [method@Service.prompt] will be used to handle * any prompts that show up. */ void secret_service_lock (SecretService *service, GList *objects, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); service_xlock_async (service, TRUE, objects, cancellable, callback, user_data); } /** * secret_service_lock_finish: * @service: (nullable): the secret service * @result: asynchronous result passed to the callback * @locked: (out) (element-type Gio.DBusProxy) (transfer full) (nullable) (optional): * location to place list of items or collections that were locked * @error: location to place an error on failure * * Complete asynchronous operation to lock items or collections in the secret * service. * * The secret service may not be able to lock items individually, and may * lock an entire collection instead. * * Returns: the number of items or collections that were locked */ gint secret_service_lock_finish (SecretService *service, GAsyncResult *result, GList **locked, GError **error) { g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); return service_xlock_finish (service, result, locked, error); } /** * secret_service_lock_sync: * @service: (nullable): the secret service * @objects: (element-type Gio.DBusProxy): the items or collections to lock * @cancellable: (nullable): optional cancellation object * @locked: (out) (element-type Gio.DBusProxy) (transfer full) (nullable) (optional): * location to place list of items or collections that were locked * @error: location to place an error on failure * * Lock items or collections in the secret service. * * The secret service may not be able to lock items individually, and may * lock an entire collection instead. * * If @service is %NULL, then [func@Service.get_sync] will be called to get * the default [class@Service] proxy. * * This method may block indefinitely and should not be used in user * interface threads. The secret service may prompt the user. * [method@Service.prompt] will be used to handle any prompts that show up. * * Returns: the number of items or collections that were locked */ gint secret_service_lock_sync (SecretService *service, GList *objects, GCancellable *cancellable, GList **locked, GError **error) { SecretSync *sync; gint count; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_lock (service, objects, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); count = secret_service_lock_finish (service, sync->result, locked, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return count; } /** * secret_service_unlock: * @service: (nullable): the secret service * @objects: (element-type Gio.DBusProxy): the items or collections to unlock * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Unlock items or collections in the secret service. * * The secret service may not be able to unlock items individually, and may * unlock an entire collection instead. * * If @service is %NULL, then [func@Service.get] will be called to get * the default [class@Service] proxy. * * This method may block indefinitely and should not be used in user * interface threads. The secret service may prompt the user. * [method@Service.prompt] will be used to handle any prompts that show up. */ void secret_service_unlock (SecretService *service, GList *objects, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); service_xlock_async (service, FALSE, objects, cancellable, callback, user_data); } /** * secret_service_unlock_finish: * @service: (nullable): the secret service * @result: asynchronous result passed to the callback * @unlocked: (out) (element-type Gio.DBusProxy) (transfer full) (nullable) (optional): * location to place list of items or collections that were unlocked * @error: location to place an error on failure * * Complete asynchronous operation to unlock items or collections in the secret * service. * * The secret service may not be able to unlock items individually, and may * unlock an entire collection instead. * * Returns: the number of items or collections that were unlocked */ gint secret_service_unlock_finish (SecretService *service, GAsyncResult *result, GList **unlocked, GError **error) { g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); return service_xlock_finish (service, result, unlocked, error); } /** * secret_service_unlock_sync: * @service: (nullable): the secret service * @objects: (element-type Gio.DBusProxy): the items or collections to unlock * @cancellable: (nullable): optional cancellation object * @unlocked: (out) (element-type Gio.DBusProxy) (transfer full) (nullable) (optional): * location to place list of items or collections that were unlocked * @error: location to place an error on failure * * Unlock items or collections in the secret service. * * The secret service may not be able to unlock items individually, and may * unlock an entire collection instead. * * If @service is %NULL, then [func@Service.get_sync] will be called to get * the default [class@Service] proxy. * * This method may block indefinitely and should not be used in user * interface threads. The secret service may prompt the user. * [method@Service.prompt] will be used to handle any prompts that show up. * * Returns: the number of items or collections that were unlocked */ gint secret_service_unlock_sync (SecretService *service, GList *objects, GCancellable *cancellable, GList **unlocked, GError **error) { SecretSync *sync; gint count; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_unlock (service, objects, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); count = secret_service_unlock_finish (service, sync->result, unlocked, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return count; } typedef struct { gchar *collection_path; SecretValue *value; GHashTable *properties; gboolean created_collection; gboolean unlocked_collection; } StoreClosure; static void store_closure_free (gpointer data) { StoreClosure *store = data; g_free (store->collection_path); secret_value_unref (store->value); g_hash_table_unref (store->properties); g_free (store); } static void on_store_create (GObject *source, GAsyncResult *result, gpointer user_data); static void on_store_keyring (GObject *source, GAsyncResult *result, gpointer user_data) { SecretService *service = SECRET_SERVICE (source); GTask *task = G_TASK (user_data); StoreClosure *store = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; gchar *path; path = secret_service_create_collection_dbus_path_finish (service, result, &error); if (error == NULL) { store->created_collection = TRUE; secret_service_create_item_dbus_path (service, store->collection_path, store->properties, store->value, SECRET_ITEM_CREATE_REPLACE, cancellable, on_store_create, g_steal_pointer (&task)); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_free (path); g_clear_object (&task); } static void on_store_unlock (GObject *source, GAsyncResult *result, gpointer user_data) { SecretService *service = SECRET_SERVICE (source); GTask *task = G_TASK (user_data); StoreClosure *store = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; secret_service_unlock_dbus_paths_finish (service, result, NULL, &error); if (error == NULL) { store->unlocked_collection = TRUE; secret_service_create_item_dbus_path (service, store->collection_path, store->properties, store->value, SECRET_ITEM_CREATE_REPLACE, cancellable, on_store_create, g_steal_pointer (&task)); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } static void on_store_create (GObject *source, GAsyncResult *result, gpointer user_data) { SecretService *service = SECRET_SERVICE (source); GTask *task = G_TASK (user_data); StoreClosure *store = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; GHashTable *properties; _secret_service_create_item_dbus_path_finish_raw (result, &error); /* * This happens when the collection doesn't exist. If the collection is * the default alias, we should try and create it */ if (!store->created_collection && (g_error_matches (error, SECRET_ERROR, SECRET_ERROR_NO_SUCH_OBJECT) || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD) || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_OBJECT)) && g_strcmp0 (store->collection_path, SECRET_ALIAS_PREFIX "default") == 0) { properties = _secret_collection_properties_new (_("Default keyring")); secret_service_create_collection_dbus_path (service, properties, "default", SECRET_COLLECTION_CREATE_NONE, cancellable, on_store_keyring, g_steal_pointer (&task)); g_hash_table_unref (properties); g_error_free (error); g_clear_object (&task); return; } if (!store->unlocked_collection && g_error_matches (error, SECRET_ERROR, SECRET_ERROR_IS_LOCKED)) { const gchar *paths[2] = { store->collection_path, NULL }; secret_service_unlock_dbus_paths (service, paths, cancellable, on_store_unlock, g_steal_pointer (&task)); g_error_free (error); g_clear_object (&task); return; } if (error != NULL) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_boolean (task, TRUE); g_clear_object (&task); } static void on_store_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); StoreClosure *store = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); SecretService *service; GError *error = NULL; service = secret_service_get_finish (result, &error); if (error == NULL) { secret_service_create_item_dbus_path (service, store->collection_path, store->properties, store->value, SECRET_ITEM_CREATE_REPLACE, cancellable, on_store_create, g_steal_pointer (&task)); g_object_unref (service); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } /** * secret_service_store: * @service: (nullable): the secret service * @schema: (nullable): the schema to use to check attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @value: the secret value * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Store a secret value in the secret service. * * The @attributes should be a set of key and value string pairs. * * If the attributes match a secret item already stored in the collection, then * the item will be updated with these new values. * * If @service is %NULL, then [func@Service.get] will be called to get * the default [class@Service] proxy. * * If @collection is not specified, then the default collection will be * used. Use [const@COLLECTION_SESSION] to store the password in the session * collection, which doesn't get stored across login sessions. * * This method will return immediately and complete asynchronously. */ void secret_service_store (SecretService *service, const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; StoreClosure *store; const gchar *schema_name; GVariant *propval; g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (attributes != NULL); g_return_if_fail (label != NULL); g_return_if_fail (value != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; task = g_task_new (service, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_store); store = g_new0 (StoreClosure, 1); store->collection_path = _secret_util_collection_to_path (collection); store->value = secret_value_ref (value); store->properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_variant_unref); propval = g_variant_new_string (label); g_hash_table_insert (store->properties, SECRET_ITEM_INTERFACE ".Label", g_variant_ref_sink (propval)); /* Always store the schema name in the attributes */ schema_name = (schema == NULL) ? NULL : schema->name; propval = _secret_attributes_to_variant (attributes, schema_name); g_hash_table_insert (store->properties, SECRET_ITEM_INTERFACE ".Attributes", g_variant_ref_sink (propval)); g_task_set_task_data (task, store, store_closure_free); if (service == NULL) { secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable, on_store_service, g_steal_pointer (&task)); } else { secret_service_create_item_dbus_path (service, store->collection_path, store->properties, store->value, SECRET_ITEM_CREATE_REPLACE, cancellable, on_store_create, g_steal_pointer (&task)); } g_clear_object (&task); } /** * secret_service_store_finish: * @service: (nullable): the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish asynchronous operation to store a secret value in the secret service. * * Returns: whether the storage was successful or not */ gboolean secret_service_store_finish (SecretService *service, GAsyncResult *result, GError **error) { g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); g_return_val_if_fail (g_task_is_valid (result, service), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_service_store_sync: * @service: (nullable): the secret service * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @value: the secret value * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Store a secret value in the secret service. * * The @attributes should be a set of key and value string pairs. * * If the attributes match a secret item already stored in the collection, then * the item will be updated with these new values. * * If @collection is %NULL, then the default collection will be * used. Use [const@COLLECTION_SESSION] to store the password in the session * collection, which doesn't get stored across login sessions. * * If @service is %NULL, then [func@Service.get_sync] will be called to get * the default [class@Service] proxy. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the storage was successful or not */ gboolean secret_service_store_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); g_return_val_if_fail (attributes != NULL, FALSE); g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return FALSE; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_store (service, schema, attributes, collection, label, value, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_service_store_finish (service, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } static void on_lookup_get_secret (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretService *self = SECRET_SERVICE (source); SecretValue *value; GError *error = NULL; value = secret_service_get_secret_for_dbus_path_finish (self, result, &error); if (error != NULL) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_pointer (task, value, secret_value_unref); g_clear_object (&task); } static void on_lookup_unlocked (GObject *source, GAsyncResult *result, gpointer user_data) { SecretService *self = SECRET_SERVICE (source); GTask *task = G_TASK (user_data); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; gchar **unlocked = NULL; secret_service_unlock_dbus_paths_finish (self, result, &unlocked, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else if (unlocked && unlocked[0]) { secret_service_get_secret_for_dbus_path (self, unlocked[0], cancellable, on_lookup_get_secret, g_steal_pointer (&task)); } else { g_task_return_pointer (task, NULL, NULL); } g_strfreev (unlocked); g_clear_object (&task); } static void on_lookup_searched (GObject *source, GAsyncResult *result, gpointer user_data) { SecretService *self = SECRET_SERVICE (source); GTask *task = G_TASK (user_data); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; gchar **unlocked = NULL; gchar **locked = NULL; secret_service_search_for_dbus_paths_finish (self, result, &unlocked, &locked, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else if (unlocked && unlocked[0]) { secret_service_get_secret_for_dbus_path (self, unlocked[0], cancellable, on_lookup_get_secret, g_steal_pointer (&task)); } else if (locked && locked[0]) { const gchar *paths[] = { locked[0], NULL }; secret_service_unlock_dbus_paths (self, paths, cancellable, on_lookup_unlocked, g_steal_pointer (&task)); } else { g_task_return_pointer (task, NULL, NULL); } g_strfreev (unlocked); g_strfreev (locked); g_clear_object (&task); } static void on_lookup_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GVariant *attributes = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); SecretService *service; GError *error = NULL; service = secret_service_get_finish (result, &error); if (error == NULL) { _secret_service_search_for_paths_variant (service, attributes, cancellable, on_lookup_searched, g_steal_pointer (&task)); g_object_unref (service); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } /** * secret_service_lookup: * @service: (nullable): the secret service * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Lookup a secret value in the secret service. * * The @attributes should be a set of key and value string pairs. * * If @service is %NULL, then [func@Service.get] will be called to get * the default [class@Service] proxy. * * This method will return immediately and complete asynchronously. */ void secret_service_lookup (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { const gchar *schema_name = NULL; GTask *task; GVariant *attributes_v; g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) schema_name = schema->name; task = g_task_new (service, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_lookup); attributes_v = _secret_attributes_to_variant (attributes, schema_name); g_variant_ref_sink (attributes_v); g_task_set_task_data (task, attributes_v, (GDestroyNotify) g_variant_unref); if (service == NULL) { secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable, on_lookup_service, g_steal_pointer (&task)); } else { _secret_service_search_for_paths_variant (service, attributes_v, cancellable, on_lookup_searched, g_steal_pointer (&task)); } g_clear_object (&task); } /** * secret_service_lookup_finish: * @service: (nullable): the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish asynchronous operation to lookup a secret value in the secret service. * * If no secret is found then %NULL is returned. * * Returns: (transfer full): a newly allocated [struct@Value], which should be * released with [method@Value.unref], or %NULL if no secret found */ SecretValue * secret_service_lookup_finish (SecretService *service, GAsyncResult *result, GError **error) { SecretValue *value; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (g_task_is_valid (result, service), NULL); value = g_task_propagate_pointer (G_TASK (result), error); if (!value) { _secret_util_strip_remote_error (error); return NULL; } return value; } /** * secret_service_lookup_sync: * @service: (nullable): the secret service * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Lookup a secret value in the secret service. * * The @attributes should be a set of key and value string pairs. * * If @service is %NULL, then [func@Service.get_sync] will be called to get * the default [class@Service] proxy. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): a newly allocated [struct@Value], which should be * released with [method@Value.unref], or %NULL if no secret found */ SecretValue * secret_service_lookup_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error) { SecretSync *sync; SecretValue *value; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return NULL; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_lookup (service, schema, attributes, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); value = secret_service_lookup_finish (service, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return value; } typedef struct { SecretService *service; GVariant *attributes; gint deleted; gint deleting; } DeleteClosure; static void delete_closure_free (gpointer data) { DeleteClosure *closure = data; if (closure->service) g_object_unref (closure->service); g_variant_unref (closure->attributes); g_free (closure); } static void on_delete_password_complete (GObject *source, GAsyncResult *result, gpointer user_data) { SecretService *service = SECRET_SERVICE (source); GTask *task = G_TASK (user_data); DeleteClosure *closure = g_task_get_task_data (task); GError *error = NULL; gboolean deleted; closure->deleting--; deleted = _secret_service_delete_path_finish (service, result, &error); if (error != NULL) g_task_return_error (task, g_steal_pointer (&error)); if (deleted) closure->deleted++; if (closure->deleting <= 0) g_task_return_boolean (task, TRUE); g_clear_object (&task); } static void on_delete_searched (GObject *source, GAsyncResult *result, gpointer user_data) { SecretService *service = SECRET_SERVICE (source); GTask *task = G_TASK (user_data); DeleteClosure *closure = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; gchar **unlocked = NULL; gint i; secret_service_search_for_dbus_paths_finish (service, result, &unlocked, NULL, &error); if (error == NULL) { for (i = 0; unlocked[i] != NULL; i++) { _secret_service_delete_path (closure->service, unlocked[i], TRUE, cancellable, on_delete_password_complete, g_object_ref (task)); closure->deleting++; } if (closure->deleting == 0) g_task_return_boolean (task, FALSE); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_strfreev (unlocked); g_clear_object (&task); } static void on_delete_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); DeleteClosure *closure = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; closure->service = secret_service_get_finish (result, &error); if (error == NULL) { _secret_service_search_for_paths_variant (closure->service, closure->attributes, cancellable, on_delete_searched, g_steal_pointer (&task)); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } /** * secret_service_clear: * @service: (nullable): the secret service * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Remove unlocked items which match the attributes from the secret service. * * The @attributes should be a set of key and value string pairs. * * If @service is %NULL, then [func@Service.get] will be called to get * the default [class@Service] proxy. * * This method will return immediately and complete asynchronously. */ void secret_service_clear (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { const gchar *schema_name = NULL; GTask *task; DeleteClosure *closure; g_return_if_fail (service == NULL || SECRET_SERVICE (service)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) schema_name = schema->name; task = g_task_new (service, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_clear); closure = g_new0 (DeleteClosure, 1); closure->attributes = _secret_attributes_to_variant (attributes, schema_name); g_variant_ref_sink (closure->attributes); g_task_set_task_data (task, closure, delete_closure_free); /* A double check to make sure we don't delete everything, should have been checked earlier */ g_assert (g_variant_n_children (closure->attributes) > 0); if (service == NULL) { secret_service_get (SECRET_SERVICE_NONE, cancellable, on_delete_service, g_steal_pointer (&task)); } else { closure->service = g_object_ref (service); _secret_service_search_for_paths_variant (closure->service, closure->attributes, cancellable, on_delete_searched, g_steal_pointer (&task)); } g_clear_object (&task); } /** * secret_service_clear_finish: * @service: (nullable): the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish asynchronous operation to remove items from the secret * service. * * Returns: whether items were removed or not */ gboolean secret_service_clear_finish (SecretService *service, GAsyncResult *result, GError **error) { g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_task_is_valid (result, service), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_service_clear_sync: * @service: (nullable): the secret service * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Remove unlocked items which match the attributes from the secret service. * * The @attributes should be a set of key and value string pairs. * * If @service is %NULL, then [func@Service.get_sync] will be called to get * the default [class@Service] proxy. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether items were removed or not */ gboolean secret_service_clear_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean result; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_clear (service, schema, attributes, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); result = secret_service_clear_finish (service, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return result; } typedef struct { gchar *alias; gchar *collection_path; } SetClosure; static void set_closure_free (gpointer data) { SetClosure *set = data; g_free (set->alias); g_free (set->collection_path); g_free (set); } static void on_set_alias_done (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretService *service = SECRET_SERVICE (source); GError *error = NULL; if (secret_service_set_alias_to_dbus_path_finish (service, result, &error)) { g_task_return_boolean (task, TRUE); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } static void on_set_alias_service (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SetClosure *set = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); SecretService *service; GError *error = NULL; service = secret_service_get_finish (result, &error); if (error == NULL) { secret_service_set_alias_to_dbus_path (service, set->alias, set->collection_path, cancellable, on_set_alias_done, g_steal_pointer (&task)); g_object_unref (service); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } /** * secret_service_set_alias: * @service: (nullable): a secret service object * @alias: the alias to assign the collection to * @collection: (nullable): the collection to assign to the alias * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Assign a collection to this alias. * * Aliases help determine well known collections, such as 'default'. * * If @service is %NULL, then [func@Service.get] will be called to get * the default [class@Service] proxy. * * This method will return immediately and complete asynchronously. */ void secret_service_set_alias (SecretService *service, const gchar *alias, SecretCollection *collection, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; SetClosure *set; const gchar *path; g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (alias != NULL); g_return_if_fail (collection == NULL || SECRET_IS_COLLECTION (collection)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (service, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_set_alias); set = g_new0 (SetClosure, 1); set->alias = g_strdup (alias); if (collection) { path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)); g_return_if_fail (path != NULL); } else { path = NULL; } set->collection_path = g_strdup (path); g_task_set_task_data (task, set, set_closure_free); if (service == NULL) { secret_service_get (SECRET_SERVICE_NONE, cancellable, on_set_alias_service, g_steal_pointer (&task)); } else { secret_service_set_alias_to_dbus_path (service, set->alias, set->collection_path, cancellable, on_set_alias_done, g_steal_pointer (&task)); } g_clear_object (&task); } /** * secret_service_set_alias_finish: * @service: (nullable): a secret service object * @result: asynchronous result passed to callback * @error: location to place error on failure * * Finish an asynchronous operation to assign a collection to an alias. * * Returns: %TRUE if successful */ gboolean secret_service_set_alias_finish (SecretService *service, GAsyncResult *result, GError **error) { g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); g_return_val_if_fail (g_task_is_valid (result, service), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_service_set_alias_sync: * @service: (nullable): a secret service object * @alias: the alias to assign the collection to * @collection: (nullable): the collection to assign to the alias * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Assign a collection to this alias. Aliases help determine * well known collections, such as 'default'. * * If @service is %NULL, then [func@Service.get_sync] will be called to get * the default [class@Service] proxy. * * This method may block and should not be used in user interface threads. * * Returns: %TRUE if successful */ gboolean secret_service_set_alias_sync (SecretService *service, const gchar *alias, SecretCollection *collection, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); g_return_val_if_fail (alias != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_set_alias (service, alias, collection, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_service_set_alias_finish (service, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } 0707010000006A000081A400000000000000000000000167D9F0D90000D7AB000000000000000000000000000000000000002D00000000libsecret-0.21.7/libsecret/secret-password.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-attributes.h" #include "secret-password.h" #include "secret-private.h" #include "secret-retrievable.h" #include "secret-backend.h" #include "secret-value.h" #include /** * secret_password_store: (skip) * @schema: the schema for attributes * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @password: the null-terminated password to store * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * @...: the attribute keys and values, terminated with %NULL * * Store a password in the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the @schema. * The list of attributes should be terminated with a %NULL. * * If the attributes match a secret item already stored in the collection, then * the item will be updated with these new values. * * If @collection is %NULL, then the default collection will be * used. Use [const@COLLECTION_SESSION] to store the password in the session * collection, which doesn't get stored across login sessions. * * This method will return immediately and complete asynchronously. */ void secret_password_store (const SecretSchema *schema, const gchar *collection, const gchar *label, const gchar *password, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) { GHashTable *attributes; va_list va; g_return_if_fail (schema != NULL); g_return_if_fail (label != NULL); g_return_if_fail (password != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); va_start (va, user_data); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return; secret_password_storev (schema, attributes, collection, label, password, cancellable, callback, user_data); g_hash_table_unref (attributes); } typedef struct { const SecretSchema *schema; GHashTable *attributes; gchar *collection; gchar *label; SecretValue *value; } StoreClosure; static void store_closure_free (gpointer data) { StoreClosure *store = data; _secret_schema_unref_if_nonstatic (store->schema); g_hash_table_unref (store->attributes); g_free (store->collection); g_free (store->label); secret_value_unref (store->value); g_free (store); } static void on_store (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretBackend *backend = SECRET_BACKEND (source); SecretBackendInterface *iface; GError *error = NULL; iface = SECRET_BACKEND_GET_IFACE (backend); g_return_if_fail (iface->store_finish != NULL); if (!iface->store_finish (backend, result, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } g_task_return_boolean (task, TRUE); g_object_unref (task); } static void on_store_backend (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); StoreClosure *store = g_task_get_task_data (task); SecretBackend *backend; SecretBackendInterface *iface; GError *error = NULL; backend = secret_backend_get_finish (result, &error); if (backend == NULL) { g_task_return_error (task, error); g_object_unref (task); return; } iface = SECRET_BACKEND_GET_IFACE (backend); g_return_if_fail (iface->store != NULL); iface->store (backend, store->schema, store->attributes, store->collection, store->label, store->value, g_task_get_cancellable (task), on_store, task); } /** * secret_password_storev: (rename-to secret_password_store) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @password: the null-terminated password to store * @cancellable: (nullable): optional cancellation object * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Store a password in the secret service. * * The @attributes should be a set of key and value string pairs. * * If the attributes match a secret item already stored in the collection, then * the item will be updated with these new values. * * If @collection is %NULL, then the default collection will be * used. Use [const@COLLECTION_SESSION] to store the password in the session * collection, which doesn't get stored across login sessions. * * This method will return immediately and complete asynchronously. */ void secret_password_storev (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, const gchar *password, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { StoreClosure *store; GTask *task; g_return_if_fail (label != NULL); g_return_if_fail (password != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; task = g_task_new (NULL, cancellable, callback, user_data); store = g_new0 (StoreClosure, 1); store->schema = _secret_schema_ref_if_nonstatic (schema); store->attributes = g_hash_table_ref (attributes); store->collection = g_strdup (collection); store->label = g_strdup (label); store->value = secret_value_new (password, -1, "text/plain"); g_task_set_task_data (task, store, store_closure_free); secret_backend_get (SECRET_BACKEND_OPEN_SESSION, cancellable, on_store_backend, task); } /** * secret_password_store_binary: (skip) * @schema: the schema for attributes * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @value: a [struct@Value] * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * @...: the attribute keys and values, terminated with %NULL * * Store a password in the secret service. * * This is similar to [func@password_store], but takes a * [struct@Value] as the argument instead of a null-terminated password. * * This method will return immediately and complete asynchronously. * * Since: 0.19.0 */ void secret_password_store_binary (const SecretSchema *schema, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) { GHashTable *attributes; va_list va; g_return_if_fail (schema != NULL); g_return_if_fail (label != NULL); g_return_if_fail (value != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); va_start (va, user_data); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return; secret_password_storev_binary (schema, attributes, collection, label, value, cancellable, callback, user_data); g_hash_table_unref (attributes); } /** * secret_password_storev_binary: (rename-to secret_password_store_binary) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @value: a [struct@Value] * @cancellable: (nullable): optional cancellation object * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Store a password in the secret service. * * This is similar to [func@password_storev], but takes a * [struct@Value] as the argument instead of a null-terminated password. * * This method will return immediately and complete asynchronously. * * Since: 0.19.0 */ void secret_password_storev_binary (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { StoreClosure *store; GTask *task; g_return_if_fail (label != NULL); g_return_if_fail (value != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; task = g_task_new (NULL, cancellable, callback, user_data); store = g_new0 (StoreClosure, 1); store->schema = _secret_schema_ref_if_nonstatic (schema); store->attributes = g_hash_table_ref (attributes); store->collection = g_strdup (collection); store->label = g_strdup (label); store->value = secret_value_ref (value); g_task_set_task_data (task, store, store_closure_free); secret_backend_get (SECRET_BACKEND_OPEN_SESSION, cancellable, on_store_backend, task); } /** * secret_password_store_finish: * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish asynchronous operation to store a password in the secret service. * * Returns: whether the storage was successful or not */ gboolean secret_password_store_finish (GAsyncResult *result, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } /** * secret_password_store_sync: * @schema: the schema for attributes * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @password: the null-terminated password to store * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * @...: the attribute keys and values, terminated with %NULL * * Store a password in the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the @schema. * The list of attributes should be terminated with a %NULL. * * If the attributes match a secret item already stored in the collection, then * the item will be updated with these new values. * * If @collection is %NULL, then the default collection will be * used. Use [const@COLLECTION_SESSION] to store the password in the session * collection, which doesn't get stored across login sessions. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the storage was successful or not */ gboolean secret_password_store_sync (const SecretSchema *schema, const gchar *collection, const gchar *label, const gchar *password, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; va_list va; gboolean ret; g_return_val_if_fail (schema != NULL, FALSE); g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (password != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); va_start (va, error); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return FALSE; ret = secret_password_storev_sync (schema, attributes, collection, label, password, cancellable, error); g_hash_table_unref (attributes); return ret; } /** * secret_password_storev_sync: (rename-to secret_password_store_sync) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @password: the null-terminated password to store * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Store a password in the secret service. * * The @attributes should be a set of key and value string pairs. * * If the attributes match a secret item already stored in the collection, then * the item will be updated with these new values. * * If @collection is %NULL, then the default collection will be * used. Use [const@COLLECTION_SESSION] to store the password in the session * collection, which doesn't get stored across login sessions. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the storage was successful or not */ gboolean secret_password_storev_sync (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, const gchar *password, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (password != NULL, FALSE); g_return_val_if_fail (attributes != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return FALSE; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_password_storev (schema, attributes, collection, label, password, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_password_store_finish (sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } /** * secret_password_store_binary_sync: * @schema: the schema for attributes * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @value: a [struct@Value] * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * @...: the attribute keys and values, terminated with %NULL * * Store a password in the secret service. * * This is similar to [func@password_store_sync], but takes a * [struct@Value] as the argument instead of a null terminated password. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the storage was successful or not * * Since: 0.19.0 */ gboolean secret_password_store_binary_sync (const SecretSchema *schema, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; va_list va; gboolean ret; g_return_val_if_fail (schema != NULL, FALSE); g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); va_start (va, error); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return FALSE; ret = secret_password_storev_binary_sync (schema, attributes, collection, label, value, cancellable, error); g_hash_table_unref (attributes); return ret; } /** * secret_password_storev_binary_sync: (rename-to secret_password_store_binary_sync) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @collection: (nullable): a collection alias, or D-Bus object path of the * collection where to store the secret * @label: label for the secret * @value: a [struct@Value] * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Store a password in the secret service. * * This is similar to [func@password_storev_sync], but takes a [struct@Value] as * the argument instead of a null-terminated passwords. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the storage was successful or not * * Since: 0.19.0 */ gboolean secret_password_storev_binary_sync (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); g_return_val_if_fail (attributes != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return FALSE; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_password_storev_binary (schema, attributes, collection, label, value, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_password_store_finish (sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } /** * secret_password_lookup: (skip) * @schema: the schema for the attributes * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * @...: the attribute keys and values, terminated with %NULL * * Lookup a password in the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attributes should be terminated with a %NULL. * * If no secret is found then %NULL is returned. * * This method will return immediately and complete asynchronously. */ void secret_password_lookup (const SecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) { GHashTable *attributes; va_list va; g_return_if_fail (schema != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); va_start (va, user_data); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return; secret_password_lookupv (schema, attributes, cancellable, callback, user_data); g_hash_table_unref (attributes); } typedef struct { const SecretSchema *schema; GHashTable *attributes; } LookupClosure; static void lookup_closure_free (gpointer data) { LookupClosure *closure = data; _secret_schema_unref_if_nonstatic (closure->schema); g_hash_table_unref (closure->attributes); g_free (closure); } static void on_lookup (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretBackend *backend = SECRET_BACKEND (source); SecretBackendInterface *iface; SecretValue *value; GError *error = NULL; iface = SECRET_BACKEND_GET_IFACE (backend); g_return_if_fail (iface->store_finish != NULL); value = iface->lookup_finish (backend, result, &error); if (error) { g_task_return_error (task, error); g_object_unref (task); return; } if (value) g_task_return_pointer (task, value, secret_value_unref); else g_task_return_pointer (task, NULL, NULL); g_object_unref (task); } static void on_lookup_backend (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); LookupClosure *lookup = g_task_get_task_data (task); SecretBackend *backend; SecretBackendInterface *iface; GError *error = NULL; backend = secret_backend_get_finish (result, &error); if (backend == NULL) { g_task_return_error (task, error); g_object_unref (task); return; } iface = SECRET_BACKEND_GET_IFACE (backend); g_return_if_fail (iface->store != NULL); iface->lookup (backend, lookup->schema, lookup->attributes, g_task_get_cancellable (task), on_lookup, task); } /** * secret_password_lookupv: (rename-to secret_password_lookup) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Lookup a password in the secret service. * * The @attributes should be a set of key and value string pairs. * * If no secret is found then %NULL is returned. * * This method will return immediately and complete asynchronously. */ void secret_password_lookupv (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { LookupClosure *lookup; GTask *task; g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; task = g_task_new (NULL, cancellable, callback, user_data); lookup = g_new0 (LookupClosure, 1); lookup->schema = _secret_schema_ref_if_nonstatic (schema); lookup->attributes = g_hash_table_ref (attributes); g_task_set_task_data (task, lookup, lookup_closure_free); secret_backend_get (SECRET_BACKEND_OPEN_SESSION, cancellable, on_lookup_backend, task); } /** * secret_password_lookup_nonpageable_finish: (skip) * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish an asynchronous operation to lookup a password in the secret service. * * Returns: (transfer full): a new password string stored in nonpageable memory * which must be freed with [func@password_free] when done */ gchar * secret_password_lookup_nonpageable_finish (GAsyncResult *result, GError **error) { SecretValue *value; g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); value = g_task_propagate_pointer (G_TASK (result), error); if (value == NULL) return NULL; return _secret_value_unref_to_password (value); } /** * secret_password_lookup_binary_finish: (skip) * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish an asynchronous operation to lookup a password in the secret service. * * Returns: (transfer full): a newly allocated [struct@Value], which should be * released with [method@Value.unref], or %NULL if no secret found * * Since: 0.19.0 */ SecretValue * secret_password_lookup_binary_finish (GAsyncResult *result, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); return g_task_propagate_pointer (G_TASK (result), error); } /** * secret_password_lookup_finish: * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish an asynchronous operation to lookup a password in the secret service. * * Returns: (transfer full): a new password string which should be freed with * [func@password_free] or may be freed with [func@GLib.free] when done */ gchar * secret_password_lookup_finish (GAsyncResult *result, GError **error) { SecretValue *value; g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); value = g_task_propagate_pointer (G_TASK (result), error); if (value == NULL) return NULL; return _secret_value_unref_to_string (value); } /** * secret_password_lookup_sync: (skip) * @schema: the schema for the attributes * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * @...: the attribute keys and values, terminated with %NULL * * Lookup a password in the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attributes should be terminated with a %NULL. * * If no secret is found then %NULL is returned. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): a new password string which should be freed with * [func@password_free] or may be freed with [func@GLib.free] when done */ gchar * secret_password_lookup_sync (const SecretSchema *schema, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; gchar *password; va_list va; g_return_val_if_fail (schema != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); va_start (va, error); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return NULL; password = secret_password_lookupv_sync (schema, attributes, cancellable, error); g_hash_table_unref (attributes); return password; } /** * secret_password_lookup_nonpageable_sync: (skip) * @schema: the schema for the attributes * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * @...: the attribute keys and values, terminated with %NULL * * Lookup a password in the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attributes should be terminated with a %NULL. * * If no secret is found then %NULL is returned. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): a new password string stored in nonpageable memory * which must be freed with [func@password_free] when done */ gchar * secret_password_lookup_nonpageable_sync (const SecretSchema *schema, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; gchar *password; va_list va; g_return_val_if_fail (schema != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); va_start (va, error); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return NULL; password = secret_password_lookupv_nonpageable_sync (schema, attributes, cancellable, error); g_hash_table_unref (attributes); return password; } /** * secret_password_lookupv_nonpageable_sync: (skip) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Lookup a password in the secret service. * * The @attributes should be a set of key and value string pairs. * * If no secret is found then %NULL is returned. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): a new password string stored in non pageable memory * which should be freed with [func@password_free] when done */ gchar * secret_password_lookupv_nonpageable_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error) { SecretSync *sync; gchar *password; g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_password_lookupv (schema, attributes, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); password = secret_password_lookup_nonpageable_finish (sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return password; } /** * secret_password_lookup_binary_sync: (skip) * @schema: the schema for the attributes * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * @...: the attribute keys and values, terminated with %NULL * * Lookup a password in the secret service. * * This is similar to [func@password_lookup_sync], but returns a * [struct@Value] instead of a null-terminated password. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): a newly allocated [struct@Value], which should be * released with [method@Value.unref], or %NULL if no secret found * * Since: 0.19.0 */ SecretValue * secret_password_lookup_binary_sync (const SecretSchema *schema, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; SecretValue *value; va_list va; g_return_val_if_fail (schema != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); va_start (va, error); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return NULL; value = secret_password_lookupv_binary_sync (schema, attributes, cancellable, error); g_hash_table_unref (attributes); return value; } /** * secret_password_lookupv_binary_sync: (skip) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Lookup a password in the secret service. * * This is similar to [func@password_lookupv_sync], but returns a * [struct@Value] instead of a null-terminated password. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): a newly allocated [struct@Value], which should be * released with [method@Value.unref], or %NULL if no secret found * * Since: 0.19.0 */ SecretValue * secret_password_lookupv_binary_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error) { SecretSync *sync; SecretValue *value; g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_password_lookupv (schema, attributes, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); value = secret_password_lookup_binary_finish (sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return value; } /** * secret_password_lookupv_sync: (rename-to secret_password_lookup_sync) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Lookup a password in the secret service. * * The @attributes should be a set of key and value string pairs. * * If no secret is found then %NULL is returned. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): a new password string which should be freed with * [func@password_free] or may be freed with [func@GLib.free] when done */ gchar * secret_password_lookupv_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error) { SecretSync *sync; gchar *string; g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_password_lookupv (schema, attributes, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); string = secret_password_lookup_finish (sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return string; } /** * secret_password_clear: * @schema: the schema for the attributes * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * @...: the attribute keys and values, terminated with %NULL * * Clear unlocked matching passwords from the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attributes should be terminated with a %NULL. * * All unlocked items that match the attributes will be deleted. * * This method will return immediately and complete asynchronously. */ void secret_password_clear (const SecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) { GHashTable *attributes; va_list va; g_return_if_fail (schema != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); va_start (va, user_data); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return; secret_password_clearv (schema, attributes, cancellable, callback, user_data); g_hash_table_unref (attributes); } typedef struct { const SecretSchema *schema; GHashTable *attributes; } ClearClosure; static void clear_closure_free (gpointer data) { ClearClosure *closure = data; _secret_schema_unref_if_nonstatic (closure->schema); g_hash_table_unref (closure->attributes); g_free (closure); } static void on_clear (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretBackend *backend = SECRET_BACKEND (source); SecretBackendInterface *iface; GError *error = NULL; iface = SECRET_BACKEND_GET_IFACE (backend); g_return_if_fail (iface->clear_finish != NULL); if (!iface->clear_finish (backend, result, &error)) { if (error) g_task_return_error (task, error); else g_task_return_boolean (task, FALSE); g_object_unref (task); return; } g_task_return_boolean (task, TRUE); g_object_unref (task); } static void on_clear_backend (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); ClearClosure *clear = g_task_get_task_data (task); SecretBackend *backend; SecretBackendInterface *iface; GError *error = NULL; backend = secret_backend_get_finish (result, &error); if (backend == NULL) { g_task_return_error (task, error); g_object_unref (task); return; } iface = SECRET_BACKEND_GET_IFACE (backend); g_return_if_fail (iface->clear != NULL); iface->clear (backend, clear->schema, clear->attributes, g_task_get_cancellable (task), on_clear, task); } /** * secret_password_clearv: (rename-to secret_password_clear) * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Remove unlocked matching passwords from the secret service. * * The @attributes should be a set of key and value string pairs. * * All unlocked items that match the attributes will be deleted. * * This method will return immediately and complete asynchronously. */ void secret_password_clearv (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { ClearClosure *clear; GTask *task; g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; task = g_task_new (NULL, cancellable, callback, user_data); clear = g_new0 (ClearClosure, 1); clear->schema = _secret_schema_ref_if_nonstatic (schema); clear->attributes = g_hash_table_ref (attributes); g_task_set_task_data (task, clear, clear_closure_free); secret_backend_get (SECRET_SERVICE_NONE, cancellable, on_clear_backend, task); } /** * secret_password_clear_finish: * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish an asynchronous operation to remove passwords from the secret * service. * * Returns: whether any passwords were removed */ gboolean secret_password_clear_finish (GAsyncResult *result, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } /** * secret_password_clear_sync: * @schema: the schema for the attributes * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * @...: the attribute keys and values, terminated with %NULL * * Remove unlocked matching passwords from the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attributes should be terminated with a %NULL. * * All unlocked items that match the attributes will be deleted. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the any passwords were removed */ gboolean secret_password_clear_sync (const SecretSchema* schema, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; gboolean result; va_list va; g_return_val_if_fail (schema != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); va_start (va, error); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return FALSE; result = secret_password_clearv_sync (schema, attributes, cancellable, error); g_hash_table_unref (attributes); return result; } /** * secret_password_clearv_sync: (rename-to secret_password_clear_sync) * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Remove unlocked matching passwords from the secret service. * * The @attributes should be a set of key and value string pairs. * * All unlocked items that match the attributes will be deleted. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether any passwords were removed */ gboolean secret_password_clearv_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean result; g_return_val_if_fail (attributes != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_password_clearv (schema, attributes, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); result = secret_password_clear_finish (sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return result; } /** * secret_password_search: (skip) * @schema: the schema for the attributes * @flags: search option flags * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * @...: the attribute keys and values, terminated with %NULL * * Search for items in the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attributes should be terminated with a %NULL. * * This method will return immediately and complete asynchronously. * * Since: 0.19.0 */ void secret_password_search (const SecretSchema *schema, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) { GHashTable *attributes; va_list va; g_return_if_fail (schema != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); va_start (va, user_data); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return; secret_password_searchv (schema, attributes, flags, cancellable, callback, user_data); g_hash_table_unref (attributes); } typedef struct { const SecretSchema *schema; GHashTable *attributes; SecretSearchFlags flags; } SearchClosure; static void search_closure_free (gpointer data) { SearchClosure *closure = data; _secret_schema_unref_if_nonstatic (closure->schema); g_hash_table_unref (closure->attributes); g_free (closure); } static void object_list_free (gpointer data) { GList *list = data; g_list_free_full (list, g_object_unref); } static void on_search (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretBackend *backend = SECRET_BACKEND (source); SecretBackendInterface *iface; GError *error = NULL; GList *items; iface = SECRET_BACKEND_GET_IFACE (backend); g_return_if_fail (iface->search_finish != NULL); items = iface->search_finish (backend, result, &error); if (error) { g_task_return_error (task, error); g_object_unref (task); return; } g_task_return_pointer (task, items, object_list_free); g_object_unref (task); } static void on_search_backend (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SearchClosure *search = g_task_get_task_data (task); SecretBackend *backend; SecretBackendInterface *iface; GError *error = NULL; backend = secret_backend_get_finish (result, &error); if (backend == NULL) { g_task_return_error (task, error); g_object_unref (task); return; } iface = SECRET_BACKEND_GET_IFACE (backend); g_return_if_fail (iface->search != NULL); iface->search (backend, search->schema, search->attributes, search->flags, g_task_get_cancellable (task), on_search, task); } /** * secret_password_searchv: (rename-to secret_password_search) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @flags: search option flags * @cancellable: (nullable): optional cancellation object * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Search for items in the secret service. * * The @attributes should be a set of key and value string pairs. * * This method will return immediately and complete asynchronously. * * Since: 0.19.0 */ void secret_password_searchv (const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SearchClosure *search; GTask *task; g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; task = g_task_new (NULL, cancellable, callback, user_data); search = g_new0 (SearchClosure, 1); search->schema = _secret_schema_ref_if_nonstatic (schema); search->attributes = g_hash_table_ref (attributes); search->flags = flags; g_task_set_task_data (task, search, search_closure_free); secret_backend_get (SECRET_SERVICE_NONE, cancellable, on_search_backend, task); } /** * secret_password_search_finish: * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish an asynchronous operation to search for items in the secret service. * * Returns: (transfer full) (element-type Secret.Retrievable): a list of * [iface@Retrievable] containing attributes of the matched items * * Since: 0.19.0 */ GList * secret_password_search_finish (GAsyncResult *result, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); return g_task_propagate_pointer (G_TASK (result), error); } /** * secret_password_search_sync: (skip) * @schema: the schema for the attributes * @flags: search option flags * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * @...: the attribute keys and values, terminated with %NULL * * Search for items in the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attributes should be terminated with a %NULL. * * If no secret is found then %NULL is returned. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full) (element-type Secret.Retrievable): a list of * [iface@Retrievable] containing attributes of the matched items * * Since: 0.19.0 */ GList * secret_password_search_sync (const SecretSchema *schema, SecretSearchFlags flags, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; GList *items; va_list va; g_return_val_if_fail (schema != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); va_start (va, error); attributes = secret_attributes_buildv (schema, va); va_end (va); /* Precondition failed, already warned */ if (!attributes) return NULL; items = secret_password_searchv_sync (schema, attributes, flags, cancellable, error); g_hash_table_unref (attributes); return items; } /** * secret_password_searchv_sync: (rename-to secret_password_search_sync) * @schema: (nullable): the schema for attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @flags: search option flags * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Search for items in the secret service. * * The @attributes should be a set of key and value string pairs. * * If no secret is found then %NULL is returned. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full) (element-type Secret.Retrievable): a list of * [iface@Retrievable] containing attributes of the matched items * * Since: 0.19.0 */ GList * secret_password_searchv_sync (const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GError **error) { SecretSync *sync; GList *items; g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return NULL; sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_password_searchv (schema, attributes, flags, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); items = secret_password_search_finish (sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return items; } /** * secret_password_free: (skip) * @password: (nullable): password to free * * Clear the memory used by a password, and then free it. * * This function must be used to free nonpageable memory returned by * [func@password_lookup_nonpageable_finish], * [func@password_lookup_nonpageable_sync] or * [func@password_lookupv_nonpageable_sync]. */ void secret_password_free (gchar *password) { if (password == NULL) return; egg_secure_strfree (password); } /** * secret_password_wipe: * @password: (nullable): password to clear * * Clear the memory used by a password. */ void secret_password_wipe (gchar *password) { if (password == NULL) return; egg_secure_strclear (password); } 0707010000006B000081A400000000000000000000000167D9F0D900002E79000000000000000000000000000000000000002D00000000libsecret-0.21.7/libsecret/secret-password.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_PASSWORD_H__ #define __SECRET_PASSWORD_H__ #include G_BEGIN_DECLS #include "secret-schema.h" #include "secret-types.h" #include "secret-value.h" void secret_password_store (const SecretSchema *schema, const gchar *collection, const gchar *label, const gchar *password, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; void secret_password_storev (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, const gchar *password, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); void secret_password_store_binary (const SecretSchema *schema, const char *collection, const char *label, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; void secret_password_storev_binary (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_password_store_finish (GAsyncResult *result, GError **error); gboolean secret_password_store_sync (const SecretSchema *schema, const gchar *collection, const gchar *label, const gchar *password, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; gboolean secret_password_storev_sync (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, const gchar *password, GCancellable *cancellable, GError **error); gboolean secret_password_store_binary_sync (const SecretSchema *schema, const char *collection, const char *label, SecretValue *value, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; gboolean secret_password_storev_binary_sync (const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GError **error); void secret_password_lookup (const SecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; void secret_password_lookupv (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gchar * secret_password_lookup_finish (GAsyncResult *result, GError **error); gchar * secret_password_lookup_nonpageable_finish (GAsyncResult *result, GError **error); SecretValue *secret_password_lookup_binary_finish (GAsyncResult *result, GError **error); gchar * secret_password_lookup_sync (const SecretSchema *schema, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; gchar * secret_password_lookup_nonpageable_sync (const SecretSchema *schema, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; SecretValue *secret_password_lookup_binary_sync (const SecretSchema *schema, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; gchar * secret_password_lookupv_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); gchar * secret_password_lookupv_nonpageable_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); SecretValue *secret_password_lookupv_binary_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); void secret_password_clear (const SecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; void secret_password_clearv (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_password_clear_finish (GAsyncResult *result, GError **error); gboolean secret_password_clear_sync (const SecretSchema* schema, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; gboolean secret_password_clearv_sync (const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); void secret_password_search (const SecretSchema *schema, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; void secret_password_searchv (const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GList * secret_password_search_sync (const SecretSchema *schema, SecretSearchFlags flags, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; GList * secret_password_searchv_sync (const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GError **error); GList * secret_password_search_finish (GAsyncResult *result, GError **error); void secret_password_free (gchar *password); void secret_password_wipe (gchar *password); G_END_DECLS #endif /* __SECRET_PASSWORD_H___ */ 0707010000006C000081A400000000000000000000000167D9F0D900016A8F000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/secret-paths.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-dbus-generated.h" #include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "secret-types.h" #include "secret-value.h" /** * secret_collection_new_for_dbus_path: (skip) * @service: (nullable): a secret service object * @collection_path: the D-Bus path of the collection * @flags: options for the collection initialization * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Get a new collection proxy for a collection in the secret service. * * If @service is %NULL, then [func@Service.get] will be called to get * the default [class@Service] proxy. * * This method will return immediately and complete asynchronously. * * Stability: Unstable */ void secret_collection_new_for_dbus_path (SecretService *service, const gchar *collection_path, SecretCollectionFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GDBusProxy *proxy; g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (collection_path != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); proxy = G_DBUS_PROXY (service); g_async_initable_new_async (secret_service_get_collection_gtype (service), G_PRIORITY_DEFAULT, cancellable, callback, user_data, "g-flags", G_DBUS_CALL_FLAGS_NONE, "g-interface-info", _secret_gen_collection_interface_info (), "g-name", g_dbus_proxy_get_name (proxy), "g-connection", g_dbus_proxy_get_connection (proxy), "g-object-path", collection_path, "g-interface-name", SECRET_COLLECTION_INTERFACE, "service", service, "flags", flags, NULL); } /** * secret_collection_new_for_dbus_path_finish: (skip) * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish asynchronous operation to get a new collection proxy for a * collection in the secret service. * * Returns: (transfer full): the new collection, which should be unreferenced * with [method@GObject.Object.unref] */ SecretCollection * secret_collection_new_for_dbus_path_finish (GAsyncResult *result, GError **error) { GObject *source_object; GObject *object; g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); source_object = g_async_result_get_source_object (result); object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error); g_object_unref (source_object); if (object == NULL) return NULL; return SECRET_COLLECTION (object); } /** * secret_collection_new_for_dbus_path_sync: (skip) * @service: (nullable): a secret service object * @collection_path: the D-Bus path of the collection * @flags: options for the collection initialization * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Get a new collection proxy for a collection in the secret service. * * If @service is %NULL, then [func@Service.get_sync] will be called to get * the default [class@Service] proxy. * * This method may block indefinitely and should not be used in user interface * threads. * * Stability: Unstable * * Returns: (transfer full): the new collection, which should be unreferenced * with [method@GObject.Object.unref] */ SecretCollection * secret_collection_new_for_dbus_path_sync (SecretService *service, const gchar *collection_path, SecretCollectionFlags flags, GCancellable *cancellable, GError **error) { GDBusProxy *proxy; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (collection_path != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); proxy = G_DBUS_PROXY (service); return g_initable_new (secret_service_get_collection_gtype (service), cancellable, error, "g-flags", G_DBUS_CALL_FLAGS_NONE, "g-interface-info", _secret_gen_collection_interface_info (), "g-name", g_dbus_proxy_get_name (proxy), "g-connection", g_dbus_proxy_get_connection (proxy), "g-object-path", collection_path, "g-interface-name", SECRET_COLLECTION_INTERFACE, "service", service, "flags", flags, NULL); } /** * secret_item_new_for_dbus_path: (skip) * @service: (nullable): a secret service object * @item_path: the D-Bus path of the collection * @flags: initialization flags for the new item * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Get a new item proxy for a secret item in the secret service. * * If @service is %NULL, then [func@Service.get] will be called to get * the default [class@Service] proxy. * * This method will return immediately and complete asynchronously. * * Stability: Unstable */ void secret_item_new_for_dbus_path (SecretService *service, const gchar *item_path, SecretItemFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GDBusProxy *proxy; g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (item_path != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); proxy = G_DBUS_PROXY (service); g_async_initable_new_async (secret_service_get_item_gtype (service), G_PRIORITY_DEFAULT, cancellable, callback, user_data, "g-flags", G_DBUS_CALL_FLAGS_NONE, "g-interface-info", _secret_gen_item_interface_info (), "g-name", g_dbus_proxy_get_name (proxy), "g-connection", g_dbus_proxy_get_connection (proxy), "g-object-path", item_path, "g-interface-name", SECRET_ITEM_INTERFACE, "service", service, "flags", flags, NULL); } /** * secret_item_new_for_dbus_path_finish: (skip) * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish asynchronous operation to get a new item proxy for a secret * item in the secret service. * * Stability: Unstable * * Returns: (transfer full): the new item, which should be unreferenced * with [method@GObject.Object.unref] */ SecretItem * secret_item_new_for_dbus_path_finish (GAsyncResult *result, GError **error) { GObject *object; GObject *source_object; source_object = g_async_result_get_source_object (result); object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error); g_object_unref (source_object); if (object == NULL) return NULL; return SECRET_ITEM (object); } /** * secret_item_new_for_dbus_path_sync: (skip) * @service: (nullable): a secret service object * @item_path: the D-Bus path of the item * @flags: initialization flags for the new item * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Get a new item proxy for a secret item in the secret service. * * If @service is %NULL, then [func@Service.get_sync] will be called to get * the default [class@Service] proxy. * * This method may block indefinitely and should not be used in user interface * threads. * * Stability: Unstable * * Returns: (transfer full): the new item, which should be unreferenced * with [method@GObject.Object.unref] */ SecretItem * secret_item_new_for_dbus_path_sync (SecretService *service, const gchar *item_path, SecretItemFlags flags, GCancellable *cancellable, GError **error) { GDBusProxy *proxy; g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (item_path != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); proxy = G_DBUS_PROXY (service); return g_initable_new (secret_service_get_item_gtype (service), cancellable, error, "g-flags", G_DBUS_CALL_FLAGS_NONE, "g-interface-info", _secret_gen_item_interface_info (), "g-name", g_dbus_proxy_get_name (proxy), "g-connection", g_dbus_proxy_get_connection (proxy), "g-object-path", item_path, "g-interface-name", SECRET_ITEM_INTERFACE, "service", service, "flags", flags, NULL); } static void on_search_items_complete (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GError *error = NULL; GVariant *response; response = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else { g_task_return_pointer (task, g_steal_pointer (&response), (GDestroyNotify) g_variant_unref); } g_object_unref (task); } /** * secret_collection_search_for_dbus_paths: (skip) * @collection: the secret collection * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Search for items in @collection matching the @attributes, and return their * DBus object paths. * * Only the specified collection is searched. The @attributes should be a table * of string keys and string values. * * This function returns immediately and completes asynchronously. * * When your callback is called use [method@Collection.search_for_dbus_paths_finish] * to get the results of this function. Only the DBus object paths of the * items will be returned. If you would like [class@Item] objects to be returned * instead, then use the [method@Collection.search] function. * * Stability: Unstable */ void secret_collection_search_for_dbus_paths (SecretCollection *collection, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task = NULL; const gchar *schema_name = NULL; g_return_if_fail (SECRET_IS_COLLECTION (collection)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) schema_name = schema->name; task = g_task_new (collection, cancellable, callback, user_data); g_task_set_source_tag (task, secret_collection_search_for_dbus_paths); g_dbus_proxy_call (G_DBUS_PROXY (collection), "SearchItems", g_variant_new ("(@a{ss})", _secret_attributes_to_variant (attributes, schema_name)), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_search_items_complete, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_collection_search_for_dbus_paths_finish: (skip) * @collection: the secret collection * @result: asynchronous result passed to callback * @error: location to place error on failure * * Complete asynchronous operation to search for items in a collection. * * DBus object paths of the items will be returned. If you would to have * [class@Item] objects to be returned instead, then use the * [method@Collection.search] and [method@Collection.search_finish] functions. * * Stability: Unstable * * Returns: (transfer full) (array zero-terminated=1): an array of DBus object * paths for matching items. */ gchar ** secret_collection_search_for_dbus_paths_finish (SecretCollection *collection, GAsyncResult *result, GError **error) { GVariant *retval = NULL; gchar **paths = NULL; g_return_val_if_fail (g_task_is_valid (result, collection), NULL); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_collection_search_for_dbus_paths, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); retval = g_task_propagate_pointer (G_TASK (result), error); if (retval == NULL) { _secret_util_strip_remote_error (error); return NULL; } g_variant_get (retval, "(^ao)", &paths); g_clear_pointer (&retval, g_variant_unref); return g_steal_pointer (&paths); } /** * secret_collection_search_for_dbus_paths_sync: (skip) * @collection: the secret collection * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Search for items matching the @attributes in @collection, and return their * DBus object paths. * * The @attributes should be a table of string keys and string values. * * This function may block indefinitely. Use the asynchronous version * in user interface threads. * * DBus object paths of the items will be returned. If you would to have * [class@Item] objects to be returned instead, then use the * [method@Collection.search_sync] function. * * Stability: Unstable * * Returns: (transfer full) (array zero-terminated=1): an array of DBus object * paths for matching items. */ gchar ** secret_collection_search_for_dbus_paths_sync (SecretCollection *collection, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error) { SecretSync *sync; gchar **paths; g_return_val_if_fail (SECRET_IS_COLLECTION (collection), NULL); g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_collection_search_for_dbus_paths (collection, schema, attributes, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); paths = secret_collection_search_for_dbus_paths_finish (collection, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return paths; } /** * secret_service_search_for_dbus_paths: (skip) * @self: the secret service * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Search for items matching the @attributes, and return their D-Bus object paths. * * All collections are searched. The @attributes should be a table of string keys * and string values. * * This function returns immediately and completes asynchronously. * * When your callback is called use [method@Service.search_for_dbus_paths_finish] * to get the results of this function. Only the D-Bus object paths of the * items will be returned. If you would like [class@Item] objects to be returned * instead, then use the [method@Service.search] function. * * Stability: Unstable */ void secret_service_search_for_dbus_paths (SecretService *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { const gchar *schema_name = NULL; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) schema_name = schema->name; _secret_service_search_for_paths_variant (self, _secret_attributes_to_variant (attributes, schema_name), cancellable, callback, user_data); } void _secret_service_search_for_paths_variant (SecretService *self, GVariant *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task = NULL; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_search_for_dbus_paths); g_dbus_proxy_call (G_DBUS_PROXY (self), "SearchItems", g_variant_new ("(@a{ss})", attributes), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_search_items_complete, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_service_search_for_dbus_paths_finish: (skip) * @self: the secret service * @result: asynchronous result passed to callback * @unlocked: (out) (transfer full) (array zero-terminated=1) (optional) (nullable): * location to place an array of D-Bus object paths for matching * items which were locked. * @locked: (out) (transfer full) (array zero-terminated=1) (optional) (nullable): * location to place an array of D-Bus object paths for matching * items which were locked. * @error: location to place error on failure * * Complete asynchronous operation to search for items, and return their * D-Bus object paths. * * Matching items that are locked or unlocked, have their D-Bus paths placed * in the @locked or @unlocked arrays respectively. * * D-Bus object paths of the items will be returned in the @unlocked or * @locked arrays. If you would to have [class@Item] objects to be returned * instead, then us the [method@Service.search] and * [method@Service.search_finish] functions. * * Stability: Unstable * * Returns: whether the search was successful or not */ gboolean secret_service_search_for_dbus_paths_finish (SecretService *self, GAsyncResult *result, gchar ***unlocked, gchar ***locked, GError **error) { GVariant *response; gchar **unlocked_ret = NULL, **locked_ret = NULL; g_return_val_if_fail (g_task_is_valid (result, self), FALSE); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_service_search_for_dbus_paths, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); response = g_task_propagate_pointer (G_TASK (result), error); if (response == NULL) { _secret_util_strip_remote_error (error); return FALSE; } g_variant_get (response, "(^ao^ao)", &unlocked_ret, &locked_ret); if (unlocked) *unlocked = g_steal_pointer (&unlocked_ret); if (locked) *locked = g_steal_pointer (&locked_ret); g_strfreev (unlocked_ret); g_strfreev (locked_ret); g_variant_unref (response); return TRUE; } /** * secret_service_search_for_dbus_paths_sync: (skip) * @self: the secret service * @schema: (nullable): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @cancellable: (nullable): optional cancellation object * @unlocked: (out) (transfer full) (array zero-terminated=1) (optional) (nullable): * location to place an array of D-Bus object paths for matching * items which were locked. * @locked: (out) (transfer full) (array zero-terminated=1) (optional) (nullable): * location to place an array of D-Bus object paths for matching * items which were locked. * @error: location to place error on failure * * Search for items matching the @attributes, and return their D-Bus object * paths. * * All collections are searched. The @attributes should be a table of string * keys and string values. * * This function may block indefinitely. Use the asynchronous version * in user interface threads. * * Matching items that are locked or unlocked, have their D-Bus paths placed * in the @locked or @unlocked arrays respectively. * * D-Bus object paths of the items will be returned in the @unlocked or * @locked arrays. If you would to have [class@Item] objects to be returned * instead, then use the [method@Service.search_sync] function. * * Stability: Unstable * * Returns: whether the search was successful or not */ gboolean secret_service_search_for_dbus_paths_sync (SecretService *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, gchar ***unlocked, gchar ***locked, GError **error) { const gchar *schema_name = NULL; GVariant *response; gchar **unlocked_ret = NULL, **locked_ret = NULL; g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (attributes != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* Warnings raised already */ if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return FALSE; if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) schema_name = schema->name; response = g_dbus_proxy_call_sync (G_DBUS_PROXY (self), "SearchItems", g_variant_new ("(@a{ss})", _secret_attributes_to_variant (attributes, schema_name)), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error); if (response == NULL) return FALSE; g_variant_get (response, "(^ao^ao)", &unlocked_ret, &locked_ret); if (unlocked) *unlocked = g_steal_pointer (&unlocked_ret); if (locked) *locked = g_steal_pointer (&locked_ret); g_variant_unref (response); g_strfreev (unlocked_ret); g_strfreev (locked_ret); return TRUE; } static void on_get_secrets_complete (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GVariant *ret; GError *error = NULL; ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else { g_task_return_pointer (task, ret, (GDestroyNotify) g_variant_unref); } g_clear_object (&task); } static void on_get_secrets_session (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GVariant *item_paths = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); GError *error = NULL; const gchar *session; secret_service_ensure_session_finish (SECRET_SERVICE (source), result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else { session = secret_service_get_session_dbus_path (SECRET_SERVICE (source)); g_dbus_proxy_call (G_DBUS_PROXY (source), "GetSecrets", g_variant_new ("(@aoo)", item_paths, session), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, cancellable, on_get_secrets_complete, g_steal_pointer (&task)); } g_clear_object (&task); } /** * secret_service_get_secret_for_dbus_path: (skip) * @self: the secret service * @item_path: the D-Bus path to item to retrieve secret for * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Get the secret value for a secret item stored in the service. * * The item is represented by its D-Bus object path. If you already have a * [class@Item] proxy object, use use [method@Item.get_secret] to more simply * get its secret value. * * This function returns immediately and completes asynchronously. * * Stability: Unstable */ void secret_service_get_secret_for_dbus_path (SecretService *self, const gchar *item_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; GVariant *path_variant; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (item_path != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); path_variant = g_variant_ref_sink (g_variant_new_objv (&item_path, 1)); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_get_secret_for_dbus_path); g_task_set_task_data (task, path_variant, (GDestroyNotify) g_variant_unref); secret_service_ensure_session (self, cancellable, on_get_secrets_session, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_service_get_secret_for_dbus_path_finish: (skip) * @self: the secret service * @result: asynchronous result passed to callback * @error: location to place an error on failure * * Complete asynchronous operation to get the secret value for an * secret item stored in the service. * * Will return %NULL if the item is locked. * * Stability: Unstable * * Returns: (transfer full) (nullable): the newly allocated secret value * for the item, which should be released with [method@Value.unref] */ SecretValue * secret_service_get_secret_for_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error) { GVariant *ret; SecretValue *value; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (g_task_is_valid (result, self), NULL); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_service_get_secret_for_dbus_path, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); ret = g_task_propagate_pointer (G_TASK (result), error); if (ret == NULL) { _secret_util_strip_remote_error (error); return NULL; } value = _secret_service_decode_get_secrets_first (self, ret); g_variant_unref (ret); return value; } /** * secret_service_get_secret_for_dbus_path_sync: (skip) * @self: the secret service * @item_path: the D-Bus path to item to retrieve secret for * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Get the secret value for a secret item stored in the service. * * The item is represented by its D-Bus object path. If you already have a * [class@Item] proxy object, use use [method@Item.load_secret_sync] to more simply * get its secret value. * * This method may block indefinitely and should not be used in user interface * threads. * * Will return %NULL if the item is locked. * * Stability: Unstable * * Returns: (transfer full) (nullable): the newly allocated secret value * the item, which should be released with [method@Value.unref] */ SecretValue * secret_service_get_secret_for_dbus_path_sync (SecretService *self, const gchar *item_path, GCancellable *cancellable, GError **error) { SecretSync *sync; SecretValue *value; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (item_path != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_get_secret_for_dbus_path (self, item_path, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); value = secret_service_get_secret_for_dbus_path_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return value; } /** * secret_service_get_secrets_for_dbus_paths: (skip) * @self: the secret service * @item_paths: the D-Bus paths to items to retrieve secrets for * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Get the secret values for a secret item stored in the service. * * The items are represented by their D-Bus object paths. If you already have * [class@Item] proxy objects, use use [func@Item.load_secrets] to more simply * get their secret values. * * This function returns immediately and completes asynchronously. * * Stability: Unstable */ void secret_service_get_secrets_for_dbus_paths (SecretService *self, const gchar **item_paths, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; GVariant *paths_variant; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (item_paths != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); paths_variant = g_variant_ref_sink (g_variant_new_objv (item_paths, -1)); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_get_secret_for_dbus_path); g_task_set_task_data (task, paths_variant, (GDestroyNotify) g_variant_unref); secret_service_ensure_session (self, cancellable, on_get_secrets_session, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_service_get_secrets_for_dbus_paths_finish: (skip) * @self: the secret service * @result: asynchronous result passed to callback * @error: location to place an error on failure * * Complete asynchronous operation to get the secret values for an * secret items stored in the service. * * Items that are locked will not be included the results. * * Stability: Unstable * * Returns: (transfer full) (element-type utf8 Secret.Value): a newly * allocated hash table of item path keys to [struct@Value] * values. */ GHashTable * secret_service_get_secrets_for_dbus_paths_finish (SecretService *self, GAsyncResult *result, GError **error) { GVariant *ret; GHashTable *values; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (g_task_is_valid (result, self), NULL); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_service_get_secret_for_dbus_path, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); ret = g_task_propagate_pointer (G_TASK (result), error); if (ret == NULL) { _secret_util_strip_remote_error (error); return NULL; } values = _secret_service_decode_get_secrets_all (self, ret); g_variant_unref (ret); return values; } /** * secret_service_get_secrets_for_dbus_paths_sync: (skip) * @self: the secret service * @item_paths: the D-Bus paths to items to retrieve secrets for * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Get the secret values for a secret item stored in the service. * * The items are represented by their D-Bus object paths. If you already have * [class@Item] proxy objects, use use [func@Item.load_secrets_sync] to more * simply get their secret values. * * This method may block indefinitely and should not be used in user interface * threads. * * Items that are locked will not be included the results. * * Stability: Unstable * * Returns: (transfer full) (element-type utf8 Secret.Value): a newly * allocated hash table of item_path keys to [struct@Value] * values. */ GHashTable * secret_service_get_secrets_for_dbus_paths_sync (SecretService *self, const gchar **item_paths, GCancellable *cancellable, GError **error) { SecretSync *sync; GHashTable *secrets; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (item_paths != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_get_secrets_for_dbus_paths (self, item_paths, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); secrets = secret_service_get_secrets_for_dbus_paths_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return secrets; } typedef struct { SecretPrompt *prompt; } XlockClosure; static void xlock_closure_free (gpointer data) { XlockClosure *closure = data; g_clear_object (&closure->prompt); g_free (closure); } static void on_xlock_prompted (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretService *self = SECRET_SERVICE (source); GPtrArray *xlocked_array; GError *error = NULL; GVariantIter iter; GVariant *retval; gchar *path; retval = secret_service_prompt_finish (self, result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else { xlocked_array = g_ptr_array_new_with_free_func (g_free); g_variant_iter_init (&iter, retval); while (g_variant_iter_loop (&iter, "o", &path)) g_ptr_array_add (xlocked_array, g_strdup (path)); g_variant_unref (retval); g_task_return_pointer (task, xlocked_array, (GDestroyNotify) g_ptr_array_unref); } g_clear_object (&task); } static void on_xlock_called (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); XlockClosure *closure = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); SecretService *self = SECRET_SERVICE (g_task_get_source_object (task)); const gchar *prompt = NULL; gchar **xlocked = NULL; GError *error = NULL; GVariant *retval; guint i; retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else { g_variant_get (retval, "(^ao&o)", &xlocked, &prompt); if (_secret_util_empty_path (prompt)) { GPtrArray *xlocked_array; xlocked_array = g_ptr_array_new_with_free_func (g_free); for (i = 0; xlocked[i]; i++) g_ptr_array_add (xlocked_array, g_strdup (xlocked[i])); g_task_return_pointer (task, xlocked_array, (GDestroyNotify) g_ptr_array_unref); } else { closure->prompt = _secret_prompt_instance (self, prompt); secret_service_prompt (self, closure->prompt, G_VARIANT_TYPE ("ao"), cancellable, on_xlock_prompted, g_steal_pointer (&task)); } g_strfreev (xlocked); g_variant_unref (retval); } g_clear_object (&task); } void _secret_service_xlock_paths_async (SecretService *self, const gchar *method, const gchar **paths, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task = NULL; XlockClosure *closure; task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, _secret_service_xlock_paths_async); closure = g_new0 (XlockClosure, 1); g_task_set_task_data (task, closure, xlock_closure_free); g_dbus_proxy_call (G_DBUS_PROXY (self), method, g_variant_new ("(@ao)", g_variant_new_objv (paths, -1)), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, cancellable, on_xlock_called, g_steal_pointer (&task)); g_clear_object (&task); } gint _secret_service_xlock_paths_finish (SecretService *self, GAsyncResult *result, gchar ***xlocked, GError **error) { GPtrArray *xlocked_array = NULL; gchar **xlocked_ret = NULL; gint count; xlocked_array = g_task_propagate_pointer (G_TASK (result), error); if (xlocked_array == NULL) { _secret_util_strip_remote_error (error); return -1; } count = xlocked_array->len; /* Add NULL-terminator after storing the count, * but before getting out the raw pointer */ g_ptr_array_add (xlocked_array, NULL); xlocked_ret = (gchar **) g_ptr_array_free (xlocked_array, FALSE); if (xlocked != NULL) *xlocked = g_steal_pointer (&xlocked_ret); g_strfreev (xlocked_ret); return count; } /** * secret_service_lock_dbus_paths_sync: (skip) * @self: the secret service * @paths: (array zero-terminated=1): the D-Bus object paths of the items or collections to lock * @cancellable: (nullable): optional cancellation object * @locked: (out) (array zero-terminated=1) (transfer full) (optional) (nullable): * location to place array of D-Bus paths of items or collections * that were locked * @error: location to place an error on failure * * Lock items or collections in the secret service. * * The items or collections are represented by their D-Bus object paths. If you * already have [class@Item] and [class@Collection] proxy objects, use use * [method@Service.lock_sync] instead. * * The secret service may not be able to lock items individually, and may * lock an entire collection instead. * * This method may block indefinitely and should not be used in user * interface threads. The secret service may prompt the user. * [method@Service.prompt] will be used to handle any prompts that show up. * * Stability: Unstable * * Returns: the number of items or collections that were locked */ gint secret_service_lock_dbus_paths_sync (SecretService *self, const gchar **paths, GCancellable *cancellable, gchar ***locked, GError **error) { SecretSync *sync; gint count; g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); g_return_val_if_fail (paths != NULL, -1); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_lock_dbus_paths (self, paths, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); count = secret_service_lock_dbus_paths_finish (self, sync->result, locked, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return count; } /** * secret_service_lock_dbus_paths: (skip) * @self: the secret service * @paths: (array zero-terminated=1): the D-Bus paths for items or collections to lock * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Lock items or collections in the secret service. * * The items or collections are represented by their D-Bus object paths. If you * already have [class@Item] and [class@Collection] proxy objects, use use * [method@Service.lock] instead. * * The secret service may not be able to lock items individually, and may * lock an entire collection instead. * * This method returns immediately and completes asynchronously. The secret * service may prompt the user. [method@Service.prompt] will be used to handle * any prompts that show up. * * Stability: Unstable */ void secret_service_lock_dbus_paths (SecretService *self, const gchar **paths, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (paths != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); _secret_service_xlock_paths_async (self, "Lock", paths, cancellable, callback, user_data); } /** * secret_service_lock_dbus_paths_finish: (skip) * @self: the secret service * @result: asynchronous result passed to the callback * @locked: (out) (array zero-terminated=1) (transfer full) (optional) (nullable): * location to place array of D-Bus paths of items or collections * that were locked * @error: location to place an error on failure * * Complete asynchronous operation to lock items or collections in the secret * service. * * The secret service may not be able to lock items individually, and may * lock an entire collection instead. * * Stability: Unstable * * Returns: the number of items or collections that were locked */ gint secret_service_lock_dbus_paths_finish (SecretService *self, GAsyncResult *result, gchar ***locked, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); g_return_val_if_fail (locked != NULL, -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); return _secret_service_xlock_paths_finish (self, result, locked, error); } /** * secret_service_unlock_dbus_paths_sync: (skip) * @self: the secret service * @paths: (array zero-terminated=1): the D-Bus object paths of the items or * collections to unlock * @cancellable: (nullable): optional cancellation object * @unlocked: (out) (array zero-terminated=1) (transfer full) (optional) (nullable): * location to place array of D-Bus paths of items or collections * that were unlocked * @error: location to place an error on failure * * Unlock items or collections in the secret service. * * The items or collections are represented by their D-Bus object paths. If you * already have [class@Item] and [class@Collection] proxy objects, use use * [method@Service.unlock_sync] instead. * * The secret service may not be able to unlock items individually, and may * unlock an entire collection instead. * * This method may block indefinitely and should not be used in user * interface threads. The secret service may prompt the user. * [method@Service.prompt] will be used to handle any prompts that show up. * * Stability: Unstable * * Returns: the number of items or collections that were unlocked */ gint secret_service_unlock_dbus_paths_sync (SecretService *self, const gchar **paths, GCancellable *cancellable, gchar ***unlocked, GError **error) { SecretSync *sync; gint count; g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); g_return_val_if_fail (paths != NULL, -1); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_unlock_dbus_paths (self, paths, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); count = secret_service_unlock_dbus_paths_finish (self, sync->result, unlocked, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return count; } /** * secret_service_unlock_dbus_paths: (skip) * @self: the secret service * @paths: (array zero-terminated=1): the D-Bus paths for items or * collections to unlock * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Unlock items or collections in the secret service. * * The items or collections are represented by their D-Bus object paths. If you * already have [class@Item] and [class@Collection] proxy objects, use use * [method@Service.unlock] instead. * * The secret service may not be able to unlock items individually, and may * unlock an entire collection instead. * * This method returns immediately and completes asynchronously. The secret * service may prompt the user. [method@Service.prompt] will be used to handle * any prompts that show up. * * Stability: Unstable */ void secret_service_unlock_dbus_paths (SecretService *self, const gchar **paths, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (paths != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); _secret_service_xlock_paths_async (self, "Unlock", paths, cancellable, callback, user_data); } /** * secret_service_unlock_dbus_paths_finish: (skip) * @self: the secret service * @result: asynchronous result passed to the callback * @unlocked: (out) (array zero-terminated=1) (transfer full) (optional) (nullable): * location to place array of D-Bus paths of items or collections * that were unlocked * @error: location to place an error on failure * * Complete asynchronous operation to unlock items or collections in the secret * service. * * The secret service may not be able to unlock items individually, and may * unlock an entire collection instead. * * Stability: Unstable * * Returns: the number of items or collections that were unlocked */ gint secret_service_unlock_dbus_paths_finish (SecretService *self, GAsyncResult *result, gchar ***unlocked, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); return _secret_service_xlock_paths_finish (self, result, unlocked, error); } typedef struct { SecretPrompt *prompt; } DeleteClosure; static void delete_closure_free (gpointer data) { DeleteClosure *closure = data; g_clear_object (&closure->prompt); g_free (closure); } static void on_delete_prompted (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GError *error = NULL; GVariant *retval; retval = secret_service_prompt_finish (SECRET_SERVICE (source), result, &error); if (retval != NULL) g_variant_unref (retval); if (error == NULL) g_task_return_boolean (task, TRUE); else g_task_return_error (task, g_steal_pointer (&error)); g_object_unref (task); } static void on_delete_complete (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); DeleteClosure *closure = g_task_get_task_data (task); SecretService *self = SECRET_SERVICE (g_task_get_source_object (task)); GCancellable *cancellable = g_task_get_cancellable (task); const gchar *prompt_path; GError *error = NULL; GVariant *retval; retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); if (error == NULL) { g_variant_get (retval, "(&o)", &prompt_path); if (_secret_util_empty_path (prompt_path)) { g_task_return_boolean (task, TRUE); } else { closure->prompt = _secret_prompt_instance (self, prompt_path); secret_service_prompt (self, closure->prompt, NULL, cancellable, on_delete_prompted, g_steal_pointer (&task)); } g_variant_unref (retval); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } void _secret_service_delete_path (SecretService *self, const gchar *object_path, gboolean is_an_item, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task = NULL; DeleteClosure *closure; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (object_path != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, _secret_service_delete_path); closure = g_new0 (DeleteClosure, 1); g_task_set_task_data (task, closure, delete_closure_free); g_dbus_connection_call (g_dbus_proxy_get_connection (G_DBUS_PROXY (self)), g_dbus_proxy_get_name (G_DBUS_PROXY (self)), object_path, is_an_item ? SECRET_ITEM_INTERFACE : SECRET_COLLECTION_INTERFACE, "Delete", g_variant_new ("()"), G_VARIANT_TYPE ("(o)"), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, cancellable, on_delete_complete, g_steal_pointer (&task)); g_clear_object (&task); } gboolean _secret_service_delete_path_finish (SecretService *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_task_is_valid (result, self), FALSE); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == _secret_service_delete_path, FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_service_delete_item_dbus_path: (skip) * @self: the secret service * @item_path: the D-Bus path of item to delete * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Delete a secret item from the secret service. * * The item is represented by its D-Bus object path. If you already have a * [class@Item] proxy objects, use use [method@Item.delete] instead. * * This method will return immediately and complete asynchronously. * * Stability: Unstable */ void secret_service_delete_item_dbus_path (SecretService *self, const gchar *item_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (item_path != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); _secret_service_delete_path (self, item_path, TRUE, cancellable, callback, user_data); } /** * secret_service_delete_item_dbus_path_finish: (skip) * @self: the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Complete an asynchronous operation to delete a secret item from the secret * service. * * Stability: Unstable * * Returns: whether the deletion was successful or not */ gboolean secret_service_delete_item_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error) { return _secret_service_delete_path_finish (self, result, error); } /** * secret_service_delete_item_dbus_path_sync: (skip) * @self: the secret service * @item_path: the D-Bus path of item to delete * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Delete a secret item from the secret service. * * The item is represented by its D-Bus object path. If you already have a * [class@Item] proxy objects, use use [method@Item.delete_sync] instead. * * This method may block indefinitely and should not be used in user interface * threads. * * Stability: Unstable * * Returns: whether the deletion was successful or not */ gboolean secret_service_delete_item_dbus_path_sync (SecretService *self, const gchar *item_path, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean result; g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (item_path != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_delete_item_dbus_path (self, item_path, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); result = secret_service_delete_item_dbus_path_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return result; } typedef struct { SecretPrompt *prompt; } CollectionClosure; static void collection_closure_free (gpointer data) { CollectionClosure *closure = data; g_clear_object (&closure->prompt); g_free (closure); } static void on_create_collection_prompt (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GError *error = NULL; GVariant *value; gchar *collection_path; value = secret_service_prompt_finish (SECRET_SERVICE (source), result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else { collection_path = g_variant_dup_string (value, NULL); g_task_return_pointer (task, collection_path, g_free); g_variant_unref (value); } g_clear_object (&task); } static void on_create_collection_called (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); CollectionClosure *closure = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); SecretService *self = SECRET_SERVICE (g_task_get_source_object (task)); const gchar *prompt_path = NULL; const gchar *collection_path = NULL; GError *error = NULL; GVariant *retval; retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); if (error == NULL) { g_variant_get (retval, "(&o&o)", &collection_path, &prompt_path); if (!_secret_util_empty_path (prompt_path)) { closure->prompt = _secret_prompt_instance (self, prompt_path); secret_service_prompt (self, closure->prompt, G_VARIANT_TYPE ("o"), cancellable, on_create_collection_prompt, g_steal_pointer (&task)); } else { g_task_return_pointer (task, g_strdup (collection_path), g_free); } g_variant_unref (retval); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } /** * secret_service_create_collection_dbus_path: (skip) * @self: a secret service object * @properties: (element-type utf8 GLib.Variant): hash table of properties for * the new collection * @alias: (nullable): an alias to check for before creating the new * collection, or to assign to the new collection * @flags: not currently used * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Create a new collection in the secret service, and return its path. * * Using this method requires that you setup a correct hash table of D-Bus * properties for the new collection. You may prefer to use * [func@Collection.create] which does handles this for you. * * An @alias is a well-known tag for a collection, such as 'default' (ie: the * default collection to store items in). This allows other applications to * easily identify and share a collection. If a collection with the @alias * already exists, then instead of creating a new collection, the existing * collection will be returned. If no collection with this alias exists, then a * new collection will be created and this alias will be assigned to it. * * @properties is a set of properties for the new collection. The keys in the * hash table should be interface.property strings like * `org.freedesktop.Secret.Collection.Label`. The values * in the hash table should be [struct@GLib.Variant] values of the properties. * * If you wish to have a * * This method will return immediately and complete asynchronously. The secret * service may prompt the user. [method@Service.prompt] will be used to handle * any prompts that are required. * * Stability: Unstable */ void secret_service_create_collection_dbus_path (SecretService *self, GHashTable *properties, const gchar *alias, SecretCollectionCreateFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task = NULL; CollectionClosure *closure; GVariant *params; GVariant *props; GDBusProxy *proxy; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (properties != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); if (alias == NULL) alias = ""; task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_create_collection_dbus_path); closure = g_new0 (CollectionClosure, 1); g_task_set_task_data (task, closure, collection_closure_free); props = _secret_util_variant_for_properties (properties); params = g_variant_new ("(@a{sv}s)", props, alias); proxy = G_DBUS_PROXY (self); g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), g_dbus_proxy_get_name (proxy), g_dbus_proxy_get_object_path (proxy), SECRET_SERVICE_INTERFACE, "CreateCollection", params, G_VARIANT_TYPE ("(oo)"), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_create_collection_called, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_service_create_collection_dbus_path_finish: (skip) * @self: a secret service object * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish asynchronous operation to create a new collection in the secret * service. * * Stability: Unstable * * Returns: (transfer full): a new string containing the D-Bus object path * of the collection */ gchar * secret_service_create_collection_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error) { gchar *path; g_return_val_if_fail (g_task_is_valid (result, self), NULL); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_service_create_collection_dbus_path, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); path = g_task_propagate_pointer (G_TASK (result), error); if (path == NULL) { _secret_util_strip_remote_error (error); return NULL; } return g_steal_pointer (&path); } /** * secret_service_create_collection_dbus_path_sync: (skip) * @self: a secret service object * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties * for the new collection * @alias: (nullable): an alias to check for before creating the new * collection, or to assign to the new collection * @flags: not currently used * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Create a new collection in the secret service and return its path. * * Using this method requires that you setup a correct hash table of D-Bus * properties for the new collection. You may prefer to use * [func@Collection.create] which does handles this for you. * * An @alias is a well-known tag for a collection, such as 'default' (ie: the * default collection to store items in). This allows other applications to * easily identify and share a collection. If a collection with the @alias * already exists, then instead of creating a new collection, the existing * collection will be returned. If no collection with this alias exists, then * a new collection will be created and this alias will be assigned to it. * * @properties is a set of properties for the new collection. The keys in the * hash table should be interface.property strings like * `org.freedesktop.Secret.Collection.Label`. The values * in the hash table should be [struct@GLib.Variant] values of the properties. * * This method may block indefinitely and should not be used in user interface * threads. The secret service may prompt the user. [method@Service.prompt] * will be used to handle any prompts that are required. * * Stability: Unstable * * Returns: (transfer full): a new string containing the D-Bus object path * of the collection */ gchar * secret_service_create_collection_dbus_path_sync (SecretService *self, GHashTable *properties, const gchar *alias, SecretCollectionCreateFlags flags, GCancellable *cancellable, GError **error) { SecretSync *sync; gchar *path; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (properties != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_create_collection_dbus_path (self, properties, alias, flags, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); path = secret_service_create_collection_dbus_path_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return path; } typedef struct { GVariant *properties; SecretValue *value; gboolean replace; gchar *collection_path; SecretPrompt *prompt; } ItemClosure; static void item_closure_free (gpointer data) { ItemClosure *closure = data; g_variant_unref (closure->properties); secret_value_unref (closure->value); g_free (closure->collection_path); g_clear_object (&closure->prompt); g_free (closure); } static void on_create_item_prompt (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GError *error = NULL; GVariant *value; gchar *item_path; value = secret_service_prompt_finish (SECRET_SERVICE (source), result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else { item_path = g_variant_dup_string (value, NULL); g_variant_unref (value); g_task_return_pointer (task, item_path, g_free); } g_clear_object (&task); } static void on_create_item_called (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); ItemClosure *closure = g_task_get_task_data (task); SecretService *self = SECRET_SERVICE (g_task_get_source_object (task)); GCancellable *cancellable = g_task_get_cancellable (task); const gchar *prompt_path = NULL; const gchar *item_path = NULL; GError *error = NULL; GVariant *retval; retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); if (error == NULL) { g_variant_get (retval, "(&o&o)", &item_path, &prompt_path); if (!_secret_util_empty_path (prompt_path)) { closure->prompt = _secret_prompt_instance (self, prompt_path); secret_service_prompt (self, closure->prompt, G_VARIANT_TYPE ("o"), cancellable, on_create_item_prompt, g_steal_pointer (&task)); } else { g_task_return_pointer (task, g_strdup (item_path), g_free); } g_variant_unref (retval); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } static void on_create_item_session (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); ItemClosure *closure = g_task_get_task_data (task); SecretService *self = SECRET_SERVICE (source); GCancellable *cancellable = g_task_get_cancellable (task); SecretSession *session; GVariant *params; GError *error = NULL; GDBusProxy *proxy; secret_service_ensure_session_finish (self, result, &error); if (error == NULL) { session = _secret_service_get_session (self); params = g_variant_new ("(@a{sv}@(oayays)b)", closure->properties, _secret_session_encode_secret (session, closure->value), closure->replace); proxy = G_DBUS_PROXY (self); g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), g_dbus_proxy_get_name (proxy), closure->collection_path, SECRET_COLLECTION_INTERFACE, "CreateItem", params, G_VARIANT_TYPE ("(oo)"), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_create_item_called, g_steal_pointer (&task)); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_clear_object (&task); } /** * secret_service_create_item_dbus_path: (skip) * @self: a secret service object * @collection_path: the D-Bus object path of the collection in which to create item * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties * for the new collection * @value: the secret value to store in the item * @flags: flags for the creation of the new item * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Create a new item in a secret service collection and return its D-Bus * object path. * * It is often easier to use [func@password_store] or [func@Item.create] * rather than using this function. Using this method requires that you setup * a correct hash table of D-Bus @properties for the new collection. * * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret * service will search for an item matching the @attributes, and update that item * instead of creating a new one. * * @properties is a set of properties for the new collection. The keys in the * hash table should be interface.property strings like * `org.freedesktop.Secret.Item.Label`. The values * in the hash table should be [struct@GLib.Variant] values of the properties. * * This method will return immediately and complete asynchronously. The secret * service may prompt the user. [method@Service.prompt] will be used to handle * any prompts that are required. * * Stability: Unstable */ void secret_service_create_item_dbus_path (SecretService *self, const gchar *collection_path, GHashTable *properties, SecretValue *value, SecretItemCreateFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task = NULL; ItemClosure *closure; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (collection_path != NULL && g_variant_is_object_path (collection_path)); g_return_if_fail (properties != NULL); g_return_if_fail (value != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_create_item_dbus_path); closure = g_new0 (ItemClosure, 1); closure->properties = _secret_util_variant_for_properties (properties); g_variant_ref_sink (closure->properties); closure->replace = flags & SECRET_ITEM_CREATE_REPLACE; closure->value = secret_value_ref (value); closure->collection_path = g_strdup (collection_path); g_task_set_task_data (task, closure, item_closure_free); secret_service_ensure_session (self, cancellable, on_create_item_session, g_steal_pointer (&task)); g_clear_object (&task); } /** * secret_service_create_item_dbus_path_finish: (skip) * @self: a secret service object * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish asynchronous operation to create a new item in the secret * service. * * Stability: Unstable * * Returns: (transfer full): a new string containing the D-Bus object path * of the item */ gchar * secret_service_create_item_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error) { gchar *path; g_return_val_if_fail (g_task_is_valid (result, self), NULL); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_service_create_item_dbus_path, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); path = g_task_propagate_pointer (G_TASK (result), error); if (path == NULL) { _secret_util_strip_remote_error (error); return NULL; } return g_steal_pointer (&path); } /* Same as the function above, but doesn't strip the remote error and throws * away the result */ void _secret_service_create_item_dbus_path_finish_raw (GAsyncResult *result, GError **error) { gchar *path; g_return_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_service_create_item_dbus_path); g_return_if_fail (error == NULL || *error == NULL); path = g_task_propagate_pointer (G_TASK (result), error); g_free (path); } /** * secret_service_create_item_dbus_path_sync: * @self: a secret service object * @collection_path: the D-Bus path of the collection in which to create item * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties * for the new collection * @value: the secret value to store in the item * @flags: flags for the creation of the new item * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Create a new item in a secret service collection and return its D-Bus * object path. * * It is often easier to use [func@password_store_sync] or [func@Item.create_sync] * rather than using this function. Using this method requires that you setup * a correct hash table of D-Bus @properties for the new collection. * * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret * service will search for an item matching the @attributes, and update that item * instead of creating a new one. * * @properties is a set of properties for the new collection. The keys in the * hash table should be interface.property strings like * `org.freedesktop.Secret.Item.Label`. The values * in the hash table should be [struct@GLib.Variant] values of the properties. * * This method may block indefinitely and should not be used in user interface * threads. The secret service may prompt the user. [method@Service.prompt] * will be used to handle any prompts that are required. * * Stability: Unstable * * Returns: (transfer full): a new string containing the D-Bus object path * of the item */ gchar * secret_service_create_item_dbus_path_sync (SecretService *self, const gchar *collection_path, GHashTable *properties, SecretValue *value, SecretItemCreateFlags flags, GCancellable *cancellable, GError **error) { SecretSync *sync; gchar *path; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (collection_path != NULL && g_variant_is_object_path (collection_path), NULL); g_return_val_if_fail (properties != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_create_item_dbus_path (self, collection_path, properties, value, flags, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); path = secret_service_create_item_dbus_path_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return path; } /** * secret_service_read_alias_dbus_path: (skip) * @self: a secret service object * @alias: the alias to lookup * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Lookup which collection is assigned to this alias. * * Aliases help determine well known collections, such as 'default'. This method * looks up the dbus object path of the well known collection. * * This method will return immediately and complete asynchronously. * * Stability: Unstable */ void secret_service_read_alias_dbus_path (SecretService *self, const gchar *alias, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (alias != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_dbus_proxy_call (G_DBUS_PROXY (self), "ReadAlias", g_variant_new ("(s)", alias), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, callback, user_data); } /** * secret_service_read_alias_dbus_path_finish: (skip) * @self: a secret service object * @result: asynchronous result passed to callback * @error: location to place error on failure * * Finish an asynchronous operation to lookup which collection is assigned * to an alias. * * This method returns the DBus object path of the collection * * Stability: Unstable * * Returns: (transfer full) (nullable): the collection dbus object path, * or %NULL if none assigned to the alias */ gchar * secret_service_read_alias_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error) { gchar *collection_path; GVariant *retval; retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, error); _secret_util_strip_remote_error (error); if (retval == NULL) return NULL; g_variant_get (retval, "(o)", &collection_path); g_variant_unref (retval); if (g_str_equal (collection_path, "/")) { g_free (collection_path); collection_path = NULL; } return collection_path; } /** * secret_service_read_alias_dbus_path_sync: (skip) * @self: a secret service object * @alias: the alias to lookup * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Lookup which collection is assigned to this alias. * * Aliases help determine well known collections, such as 'default'. This method * returns the dbus object path of the collection. * * This method may block and should not be used in user interface threads. * * Stability: Unstable * * Returns: (transfer full) (nullable): the collection dbus object path, * or %NULL if none assigned to the alias */ gchar * secret_service_read_alias_dbus_path_sync (SecretService *self, const gchar *alias, GCancellable *cancellable, GError **error) { SecretSync *sync; gchar *collection_path; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (alias != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_read_alias_dbus_path (self, alias, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); collection_path = secret_service_read_alias_dbus_path_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return collection_path; } /** * secret_service_set_alias_to_dbus_path: (skip) * @self: a secret service object * @alias: the alias to assign the collection to * @collection_path: (nullable): the dbus object path of the collection to assign to the alias * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Assign a collection to this alias. Aliases help determine * well known collections, such as 'default'. This method takes the dbus object * path of the collection to assign to the alias. * * This method will return immediately and complete asynchronously. * * Stability: Unstable */ void secret_service_set_alias_to_dbus_path (SecretService *self, const gchar *alias, const gchar *collection_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (alias != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); if (collection_path == NULL) collection_path = "/"; else g_return_if_fail (g_variant_is_object_path (collection_path)); g_dbus_proxy_call (G_DBUS_PROXY (self), "SetAlias", g_variant_new ("(so)", alias, collection_path), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, callback, user_data); } /** * secret_service_set_alias_to_dbus_path_finish: (skip) * @self: a secret service object * @result: asynchronous result passed to callback * @error: location to place error on failure * * Finish an asynchronous operation to assign a collection to an alias. * * Stability: Unstable * * Returns: %TRUE if successful */ gboolean secret_service_set_alias_to_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error) { GVariant *retval; g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, error); _secret_util_strip_remote_error (error); if (retval == NULL) return FALSE; g_variant_unref (retval); return TRUE; } /** * secret_service_set_alias_to_dbus_path_sync: (skip) * @self: a secret service object * @alias: the alias to assign the collection to * @collection_path: (nullable): the D-Bus object path of the collection to * assign to the alias * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Assign a collection to this alias. * * Aliases help determine well known collections, such as 'default'. This method * takes the dbus object path of the collection to assign to the alias. * * This method may block and should not be used in user interface threads. * * Stability: Unstable * * Returns: %TRUE if successful */ gboolean secret_service_set_alias_to_dbus_path_sync (SecretService *self, const gchar *alias, const gchar *collection_path, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (alias != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (collection_path == NULL) collection_path = "/"; else g_return_val_if_fail (g_variant_is_object_path (collection_path), FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_set_alias_to_dbus_path (self, alias, collection_path, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_service_set_alias_to_dbus_path_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } /** * secret_service_prompt_at_dbus_path_sync: (skip) * @self: the secret service * @prompt_path: the D-Bus object path of the prompt * @cancellable: (nullable): optional cancellation object * @return_type: (nullable): the variant type of the prompt result * @error: location to place error on failure * * Perform prompting for a [class@Prompt]. * * Override the #SecretServiceClass [vfunc@Service.prompt_async] virtual method * to change the behavior of the propmting. The default behavior is to simply * run [method@Prompt.perform] on the prompt. * * Returns a variant result if the prompt was completed and not dismissed. The * type of result depends on the action the prompt is completing, and is defined * in the Secret Service DBus API specification. * * This method may block and should not be used in user interface threads. * * Stability: Unstable * * Returns: (transfer full) (nullable): %NULL if the prompt was dismissed or an * error occurred, a variant result if the prompt was successful */ GVariant * secret_service_prompt_at_dbus_path_sync (SecretService *self, const gchar *prompt_path, GCancellable *cancellable, const GVariantType *return_type, GError **error) { SecretPrompt *prompt; GVariant *retval; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (prompt_path != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); prompt = _secret_prompt_instance (self, prompt_path); retval = secret_service_prompt_sync (self, prompt, cancellable, return_type, error); g_object_unref (prompt); return retval; } /** * secret_service_prompt_at_dbus_path: (skip) * @self: the secret service * @prompt_path: the D-Bus object path of the prompt * @return_type: (nullable): the variant type of the prompt result * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Perform prompting for a [class@Prompt]. * * This function is called by other parts of this library to handle prompts * for the various actions that can require prompting. * * Override the #SecretServiceClass [vfunc@Service.prompt_async] virtual method * to change the behavior of the propmting. The default behavior is to simply * run [method@Prompt.perform] on the prompt. * * Stability: Unstable */ void secret_service_prompt_at_dbus_path (SecretService *self, const gchar *prompt_path, const GVariantType *return_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretPrompt *prompt; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (prompt_path != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); prompt = _secret_prompt_instance (self, prompt_path); secret_service_prompt (self, prompt, return_type, cancellable, callback, user_data); g_object_unref (prompt); } /** * secret_service_prompt_at_dbus_path_finish: (skip) * @self: the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Complete asynchronous operation to perform prompting for a [class@Prompt]. * * Returns a variant result if the prompt was completed and not dismissed. The * type of result depends on the action the prompt is completing, and is defined * in the Secret Service DBus API specification. * * Stability: Unstable * * Returns: (transfer full) (nullable): %NULL if the prompt was dismissed or an * error occurred, a variant result if the prompt was successful */ GVariant * secret_service_prompt_at_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); return secret_service_prompt_finish (self, result, error); } /** * secret_service_encode_dbus_secret: * @service: the service * @value: the secret value * * Encodes a [struct@Value] into [struct@GLib.Variant] for use with the Secret * Service DBus API. * * The resulting [struct@GLib.Variant] will have a `(oayays)` signature. * * A session must have already been established by the [class@Service]. * * Returns: (transfer floating): the encoded secret */ GVariant * secret_service_encode_dbus_secret (SecretService *service, SecretValue *value) { SecretSession *session; g_return_val_if_fail (service != NULL, NULL); g_return_val_if_fail (value != NULL, NULL); session = _secret_service_get_session (service); g_return_val_if_fail (session != NULL, NULL); return _secret_session_encode_secret (session, value); } /** * secret_service_decode_dbus_secret: * @service: the service * @value: the encoded secret * * Decode a [struct@Value] into [struct@GLib.Variant] received with the Secret Service * DBus API. * * The [struct@GLib.Variant] should have a `(oayays)` signature. * * A session must have already been established by the [class@Service], and * the encoded secret must be valid for that session. * * Returns: (transfer full): the decoded secret value */ SecretValue * secret_service_decode_dbus_secret (SecretService *service, GVariant *value) { SecretSession *session; g_return_val_if_fail (service != NULL, NULL); g_return_val_if_fail (value != NULL, NULL); session = _secret_service_get_session (service); g_return_val_if_fail (session != NULL, NULL); return _secret_session_decode_secret (session, value); } 0707010000006D000081A400000000000000000000000167D9F0D900004E8B000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/secret-paths.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_PATHS_H__ #define __SECRET_PATHS_H__ #include #include "secret-collection.h" #include "secret-item.h" #include "secret-prompt.h" #include "secret-schema.h" #include "secret-types.h" #include "secret-value.h" G_BEGIN_DECLS void secret_collection_new_for_dbus_path (SecretService *service, const gchar *collection_path, SecretCollectionFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretCollection * secret_collection_new_for_dbus_path_finish (GAsyncResult *result, GError **error); SecretCollection * secret_collection_new_for_dbus_path_sync (SecretService *service, const gchar *collection_path, SecretCollectionFlags flags, GCancellable *cancellable, GError **error); void secret_collection_search_for_dbus_paths (SecretCollection *collection, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gchar ** secret_collection_search_for_dbus_paths_finish (SecretCollection *collection, GAsyncResult *result, GError **error); gchar ** secret_collection_search_for_dbus_paths_sync (SecretCollection *collection, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); void secret_item_new_for_dbus_path (SecretService *service, const gchar *item_path, SecretItemFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretItem * secret_item_new_for_dbus_path_finish (GAsyncResult *result, GError **error); SecretItem * secret_item_new_for_dbus_path_sync (SecretService *service, const gchar *item_path, SecretItemFlags flags, GCancellable *cancellable, GError **error); const gchar * secret_service_get_session_dbus_path (SecretService *self); void secret_service_search_for_dbus_paths (SecretService *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_service_search_for_dbus_paths_finish (SecretService *self, GAsyncResult *result, gchar ***unlocked, gchar ***locked, GError **error); gboolean secret_service_search_for_dbus_paths_sync (SecretService *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, gchar ***unlocked, gchar ***locked, GError **error); void secret_service_get_secret_for_dbus_path (SecretService *self, const gchar *item_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretValue * secret_service_get_secret_for_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error); SecretValue * secret_service_get_secret_for_dbus_path_sync (SecretService *self, const gchar *item_path, GCancellable *cancellable, GError **error); void secret_service_get_secrets_for_dbus_paths (SecretService *self, const gchar **item_paths, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GHashTable * secret_service_get_secrets_for_dbus_paths_finish (SecretService *self, GAsyncResult *result, GError **error); GHashTable * secret_service_get_secrets_for_dbus_paths_sync (SecretService *self, const gchar **item_paths, GCancellable *cancellable, GError **error); gint secret_service_lock_dbus_paths_sync (SecretService *self, const gchar **paths, GCancellable *cancellable, gchar ***locked, GError **error); void secret_service_lock_dbus_paths (SecretService *self, const gchar **paths, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gint secret_service_lock_dbus_paths_finish (SecretService *self, GAsyncResult *result, gchar ***locked, GError **error); gint secret_service_unlock_dbus_paths_sync (SecretService *self, const gchar **paths, GCancellable *cancellable, gchar ***unlocked, GError **error); void secret_service_unlock_dbus_paths (SecretService *self, const gchar **paths, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gint secret_service_unlock_dbus_paths_finish (SecretService *self, GAsyncResult *result, gchar ***unlocked, GError **error); GVariant * secret_service_prompt_at_dbus_path_sync (SecretService *self, const gchar *prompt_path, GCancellable *cancellable, const GVariantType *return_type, GError **error); void secret_service_prompt_at_dbus_path (SecretService *self, const gchar *prompt_path, const GVariantType *return_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GVariant * secret_service_prompt_at_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error); void secret_service_delete_item_dbus_path (SecretService *self, const gchar *item_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_service_delete_item_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error); gboolean secret_service_delete_item_dbus_path_sync (SecretService *self, const gchar *item_path, GCancellable *cancellable, GError **error); void secret_service_create_collection_dbus_path (SecretService *self, GHashTable *properties, const gchar *alias, SecretCollectionCreateFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gchar * secret_service_create_collection_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error); gchar * secret_service_create_collection_dbus_path_sync (SecretService *self, GHashTable *properties, const gchar *alias, SecretCollectionCreateFlags flags, GCancellable *cancellable, GError **error); void secret_service_create_item_dbus_path (SecretService *self, const gchar *collection_path, GHashTable *properties, SecretValue *value, SecretItemCreateFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gchar * secret_service_create_item_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error); gchar * secret_service_create_item_dbus_path_sync (SecretService *self, const gchar *collection_path, GHashTable *properties, SecretValue *value, SecretItemCreateFlags flags, GCancellable *cancellable, GError **error); void secret_service_read_alias_dbus_path (SecretService *self, const gchar *alias, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gchar * secret_service_read_alias_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error); gchar * secret_service_read_alias_dbus_path_sync (SecretService *self, const gchar *alias, GCancellable *cancellable, GError **error); void secret_service_set_alias_to_dbus_path (SecretService *self, const gchar *alias, const gchar *collection_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_service_set_alias_to_dbus_path_finish (SecretService *self, GAsyncResult *result, GError **error); gboolean secret_service_set_alias_to_dbus_path_sync (SecretService *self, const gchar *alias, const gchar *collection_path, GCancellable *cancellable, GError **error); GVariant * secret_service_encode_dbus_secret (SecretService *service, SecretValue *value); SecretValue * secret_service_decode_dbus_secret (SecretService *service, GVariant *value); G_END_DECLS #endif /* __SECRET_SERVICE_H___ */ 0707010000006E000081A400000000000000000000000167D9F0D900002CBB000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/secret-private.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #ifndef __SECRET_PRIVATE_H__ #define __SECRET_PRIVATE_H__ #include #include "secret-item.h" #include "secret-service.h" #include "secret-value.h" G_BEGIN_DECLS typedef struct { GAsyncResult *result; GMainContext *context; GMainLoop *loop; } SecretSync; typedef struct _SecretSession SecretSession; #define SECRET_ALIAS_PREFIX "/org/freedesktop/secrets/aliases/" #define SECRET_SERVICE_PATH "/org/freedesktop/secrets" #define SECRET_SERVICE_BUS_NAME "org.freedesktop.secrets" #define SECRET_ITEM_INTERFACE "org.freedesktop.Secret.Item" #define SECRET_COLLECTION_INTERFACE "org.freedesktop.Secret.Collection" #define SECRET_PROMPT_INTERFACE "org.freedesktop.Secret.Prompt" #define SECRET_SERVICE_INTERFACE "org.freedesktop.Secret.Service" #define SECRET_SIGNAL_COLLECTION_CREATED "CollectionCreated" #define SECRET_SIGNAL_COLLECTION_CHANGED "CollectionChanged" #define SECRET_SIGNAL_COLLECTION_DELETED "CollectionDeleted" #define SECRET_SIGNAL_ITEM_CREATED "ItemCreated" #define SECRET_SIGNAL_ITEM_CHANGED "ItemChanged" #define SECRET_SIGNAL_ITEM_DELETED "ItemDeleted" #define SECRET_PROMPT_SIGNAL_COMPLETED "Completed" #define SECRET_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" SecretSync * _secret_sync_new (void); void _secret_sync_free (gpointer data); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecretSync, _secret_sync_free) void _secret_sync_on_result (GObject *source, GAsyncResult *result, gpointer user_data); SecretPrompt * _secret_prompt_instance (SecretService *service, const gchar *prompt_path); void _secret_util_strip_remote_error (GError **error); gchar * _secret_util_parent_path (const gchar *path); gboolean _secret_util_empty_path (const gchar *path); gchar * _secret_util_collection_to_path (const gchar *collection); gint _secret_util_array_index_of (GVariant *array, GVariant *value); GType _secret_list_get_type (void) G_GNUC_CONST; GVariant * _secret_attributes_to_variant (GHashTable *attributes, const gchar *schema_name); GHashTable * _secret_attributes_for_variant (GVariant *variant); GHashTable * _secret_attributes_copy (GHashTable *attributes); gboolean _secret_attributes_validate (const SecretSchema *schema, GHashTable *attributes, const gchar *pretty_function, gboolean matching); GVariant * _secret_util_variant_for_properties (GHashTable *properties); void _secret_util_get_properties (GDBusProxy *proxy, gpointer result_tag, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean _secret_util_get_properties_finish (GDBusProxy *proxy, gpointer result_tag, GAsyncResult *result, GError **error); void _secret_util_set_property (GDBusProxy *proxy, const gchar *property, GVariant *value, gpointer result_tag, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean _secret_util_set_property_finish (GDBusProxy *proxy, gpointer result_tag, GAsyncResult *result, GError **error); gboolean _secret_util_set_property_sync (GDBusProxy *proxy, const gchar *property, GVariant *value, GCancellable *cancellable, GError **error); gboolean _secret_util_have_cached_properties (GDBusProxy *proxy); SecretSession * _secret_service_get_session (SecretService *self); void _secret_service_take_session (SecretService *self, SecretSession *session); void _secret_service_delete_path (SecretService *self, const gchar *object_path, gboolean is_an_item, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean _secret_service_delete_path_finish (SecretService *self, GAsyncResult *result, GError **error); void _secret_service_search_for_paths_variant (SecretService *self, GVariant *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretItem * _secret_service_find_item_instance (SecretService *self, const gchar *item_path); SecretCollection * _secret_service_find_collection_instance (SecretService *self, const gchar *collection_path); SecretValue * _secret_service_decode_get_secrets_first (SecretService *self, GVariant *out); GHashTable * _secret_service_decode_get_secrets_all (SecretService *self, GVariant *out); void _secret_service_xlock_paths_async (SecretService *self, const gchar *method, const gchar **paths, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gint _secret_service_xlock_paths_finish (SecretService *self, GAsyncResult *result, gchar ***xlocked, GError **error); void _secret_service_create_item_dbus_path_finish_raw (GAsyncResult *result, GError **error); GHashTable * _secret_collection_properties_new (const gchar *label); SecretItem * _secret_collection_find_item_instance (SecretCollection *self, const gchar *item_path); gchar * _secret_value_unref_to_password (SecretValue *value); gchar * _secret_value_unref_to_string (SecretValue *value); void _secret_session_free (gpointer data); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecretSession, _secret_session_free) const gchar * _secret_session_get_algorithms (SecretSession *session); const gchar * _secret_session_get_path (SecretSession *session); void _secret_session_open (SecretService *service, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean _secret_session_open_finish (GAsyncResult *result, GError **error); GVariant * _secret_session_encode_secret (SecretSession *session, SecretValue *value); SecretValue * _secret_session_decode_secret (SecretSession *session, GVariant *encoded); void _secret_item_set_cached_secret (SecretItem *self, SecretValue *value); const SecretSchema * _secret_schema_ref_if_nonstatic (const SecretSchema *schema); void _secret_schema_unref_if_nonstatic (const SecretSchema *schema); G_END_DECLS #endif /* __SECRET_PRIVATE_H___ */ 0707010000006F000081A400000000000000000000000167D9F0D900004515000000000000000000000000000000000000002B00000000libsecret-0.21.7/libsecret/secret-prompt.c/* libsecret - GLib wrapper for Secret Prompt * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-dbus-generated.h" #include "secret-private.h" #include "secret-prompt.h" #include #include /** * SecretPrompt: * * A prompt in the Service * * A proxy object representing a prompt that the Secret Service will display * to the user. * * Certain actions on the Secret Service require user prompting to complete, * such as creating a collection, or unlocking a collection. When such a prompt * is necessary, then a #SecretPrompt object is created by this library, and * passed to the [method@Service.prompt] method. In this way it is handled * automatically. * * In order to customize prompt handling, override the * [vfunc@Service.prompt_async] and [vfunc@Service.prompt_finish] virtual * methods of the [class@Service] class. * * Stability: Stable */ /** * SecretPromptClass: * @parent_class: the parent class * * The class for #SecretPrompt. */ struct _SecretPromptPrivate { gint prompted; }; G_DEFINE_TYPE_WITH_PRIVATE (SecretPrompt, secret_prompt, G_TYPE_DBUS_PROXY); static void secret_prompt_init (SecretPrompt *self) { self->pv = secret_prompt_get_instance_private (self); } static void secret_prompt_class_init (SecretPromptClass *klass) { } typedef struct { GMainLoop *loop; GAsyncResult *result; } RunClosure; static void on_prompt_run_complete (GObject *source, GAsyncResult *result, gpointer user_data) { RunClosure *closure = user_data; closure->result = g_object_ref (result); g_main_loop_quit (closure->loop); } SecretPrompt * _secret_prompt_instance (SecretService *service, const gchar *prompt_path) { GDBusProxy *proxy; SecretPrompt *prompt; GError *error = NULL; g_return_val_if_fail (SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (prompt_path != NULL, NULL); proxy = G_DBUS_PROXY (service); prompt = g_initable_new (SECRET_TYPE_PROMPT, NULL, &error, "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, "g-interface-info", _secret_gen_prompt_interface_info (), "g-name", g_dbus_proxy_get_name (proxy), "g-connection", g_dbus_proxy_get_connection (proxy), "g-object-path", prompt_path, "g-interface-name", SECRET_PROMPT_INTERFACE, NULL); if (error != NULL) { g_warning ("couldn't create SecretPrompt object: %s", error->message); g_clear_error (&error); return NULL; } return prompt; } /** * secret_prompt_run: * @self: a prompt * @window_id: (nullable): string form of XWindow id for parent window to be transient for * @cancellable: (nullable): optional cancellation object * @return_type: the variant type of the prompt result * @error: location to place an error on failure * * Runs a prompt and performs the prompting. * * Returns a variant result if the prompt was completed and not dismissed. The * type of result depends on the action the prompt is completing, and is defined * in the Secret Service DBus API specification. * * If @window_id is non-null then it is used as an XWindow id on Linux. The API * expects this id to be converted to a string using the `%d` printf format. The * Secret Service can make its prompt transient for the window with this id. In * some Secret Service implementations this is not possible, so the behavior * depending on this should degrade gracefully. * * This runs the dialog in a recursive mainloop. When run from a user interface * thread, this means the user interface will remain responsive. Care should be * taken that appropriate user interface actions are disabled while running the * prompt. * * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred */ GVariant * secret_prompt_run (SecretPrompt *self, const gchar *window_id, GCancellable *cancellable, const GVariantType *return_type, GError **error) { GMainContext *context; RunClosure *closure; GVariant *retval; g_return_val_if_fail (SECRET_IS_PROMPT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); context = g_main_context_get_thread_default (); closure = g_new0 (RunClosure, 1); closure->loop = g_main_loop_new (context, FALSE); secret_prompt_perform (self, window_id, return_type, cancellable, on_prompt_run_complete, closure); g_main_loop_run (closure->loop); retval = secret_prompt_perform_finish (self, closure->result, error); g_main_loop_unref (closure->loop); g_object_unref (closure->result); g_free (closure); return retval; } /** * secret_prompt_perform_sync: * @self: a prompt * @window_id: (nullable): string form of XWindow id for parent window to be transient for * @cancellable: (nullable): optional cancellation object * @return_type: the variant type of the prompt result * @error: location to place an error on failure * * Runs a prompt and performs the prompting. * * Returns a variant result if the prompt was completed and not dismissed. The * type of result depends on the action the prompt is completing, and is defined * in the Secret Service DBus API specification. * * If @window_id is non-null then it is used as an XWindow id on Linux. The API * expects this id to be converted to a string using the `%d` printf format. The * Secret Service can make its prompt transient for the window with this id. In * some Secret Service implementations this is not possible, so the behavior * depending on this should degrade gracefully. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred */ GVariant * secret_prompt_perform_sync (SecretPrompt *self, const gchar *window_id, GCancellable *cancellable, const GVariantType *return_type, GError **error) { GMainContext *context; GVariant *retval; g_return_val_if_fail (SECRET_IS_PROMPT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); context = g_main_context_new (); g_main_context_push_thread_default (context); retval = secret_prompt_run (self, window_id, cancellable, return_type, error); /* Needed to prevent memory leaks */ while (g_main_context_iteration (context, FALSE)); g_main_context_pop_thread_default (context); g_main_context_unref (context); return retval; } typedef struct { GDBusConnection *connection; GCancellable *call_cancellable; gulong cancelled_sig; gboolean prompting; gboolean dismissed; gboolean vanished; gboolean completed; GVariant *result; guint signal; guint watch; GVariantType *return_type; } PerformClosure; static void perform_closure_free (gpointer data) { PerformClosure *closure = data; g_object_unref (closure->call_cancellable); g_object_unref (closure->connection); if (closure->result) g_variant_unref (closure->result); if (closure->return_type) g_variant_type_free (closure->return_type); g_assert (closure->signal == 0); g_assert (closure->watch == 0); g_free (closure); } static void perform_prompt_complete (GTask *task, gboolean dismissed) { PerformClosure *closure = g_task_get_task_data (task); GCancellable *async_cancellable = g_task_get_cancellable (task); closure->dismissed = dismissed; if (closure->completed) return; closure->completed = TRUE; if (closure->signal) g_dbus_connection_signal_unsubscribe (closure->connection, closure->signal); closure->signal = 0; if (closure->watch) g_bus_unwatch_name (closure->watch); closure->watch = 0; if (closure->cancelled_sig) g_signal_handler_disconnect (async_cancellable, closure->cancelled_sig); closure->cancelled_sig = 0; } static void on_prompt_completed (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { GTask *task = G_TASK (user_data); PerformClosure *closure = g_task_get_task_data (task); gboolean dismissed; closure->prompting = FALSE; if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(bv)"))) { g_warning ("SecretPrompt received invalid %s signal of type %s", signal_name, g_variant_get_type_string (parameters)); perform_prompt_complete (task, TRUE); g_task_return_boolean (task, TRUE); } else { g_variant_get (parameters, "(bv)", &dismissed, &closure->result); perform_prompt_complete (task, dismissed); g_task_return_boolean (task, TRUE); } } static void on_prompt_prompted (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); PerformClosure *closure = g_task_get_task_data (task); SecretPrompt *self = SECRET_PROMPT (source); GError *error = NULL; GVariant *retval; retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, &error); if (retval) g_variant_unref (retval); if (closure->vanished) g_clear_error (&error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); perform_prompt_complete (task, TRUE); } else { closure->prompting = TRUE; g_atomic_int_set (&self->pv->prompted, 1); /* And now we wait for the signal */ } g_clear_object (&task); } static void on_prompt_vanished (GDBusConnection *connection, const gchar *name, gpointer user_data) { GTask *task = G_TASK (user_data); PerformClosure *closure = g_task_get_task_data (task); closure->vanished = TRUE; g_cancellable_cancel (closure->call_cancellable); perform_prompt_complete (task, TRUE); g_task_return_boolean (task, TRUE); } static void on_prompt_dismissed (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); PerformClosure *closure = g_task_get_task_data (task); SecretPrompt *self = SECRET_PROMPT (source); GError *error = NULL; GVariant *retval; retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, &error); if (retval) g_variant_unref (retval); if (closure->vanished) g_clear_error (&error); if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) g_clear_error (&error); if (error != NULL) { perform_prompt_complete (task, TRUE); g_task_return_error (task, error); } g_clear_object (&task); } static void on_prompt_cancelled (GCancellable *cancellable, gpointer user_data) { GTask *task = G_TASK (user_data); SecretPrompt *self = SECRET_PROMPT (g_task_get_source_object (task)); PerformClosure *closure = g_task_get_task_data (task); /* Instead of cancelling our dbus calls, we cancel the prompt itself via this dbus call */ g_dbus_proxy_call (G_DBUS_PROXY (self), "Dismiss", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, closure->call_cancellable, on_prompt_dismissed, g_object_ref (task)); } /** * secret_prompt_perform: * @self: a prompt * @window_id: (nullable): string form of XWindow id for parent window to be transient for * @return_type: the variant type of the prompt result * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Runs a prompt and performs the prompting. * * Returns %TRUE if the prompt was completed and not dismissed. * * If @window_id is non-null then it is used as an XWindow id on Linux. The API * expects this id to be converted to a string using the `%d` printf format. The * Secret Service can make its prompt transient for the window with this id. In * some Secret Service implementations this is not possible, so the behavior * depending on this should degrade gracefully. * * This method will return immediately and complete asynchronously. */ void secret_prompt_perform (SecretPrompt *self, const gchar *window_id, const GVariantType *return_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; PerformClosure *closure; GCancellable *async_cancellable; gchar *owner_name; const gchar *object_path; gboolean prompted; GDBusProxy *proxy; g_return_if_fail (SECRET_IS_PROMPT (self)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); prompted = g_atomic_int_get (&self->pv->prompted); if (prompted) { g_warning ("The prompt object has already had its prompt called."); return; } proxy = G_DBUS_PROXY (self); task = g_task_new (self, cancellable, callback, user_data); async_cancellable = g_task_get_cancellable (task); g_task_set_source_tag (task, secret_prompt_perform); closure = g_new0 (PerformClosure, 1); closure->connection = g_object_ref (g_dbus_proxy_get_connection (proxy)); closure->call_cancellable = g_cancellable_new (); async_cancellable = cancellable ? g_object_ref (cancellable) : NULL; closure->return_type = return_type ? g_variant_type_copy (return_type) : NULL; g_task_set_task_data (task, closure, perform_closure_free); g_task_set_check_cancellable (task, FALSE); if (window_id == NULL) window_id = ""; owner_name = g_dbus_proxy_get_name_owner (proxy); object_path = g_dbus_proxy_get_object_path (proxy); closure->signal = g_dbus_connection_signal_subscribe (closure->connection, owner_name, SECRET_PROMPT_INTERFACE, SECRET_PROMPT_SIGNAL_COMPLETED, object_path, NULL, G_DBUS_SIGNAL_FLAGS_NONE, on_prompt_completed, g_object_ref (task), g_object_unref); closure->watch = g_bus_watch_name_on_connection (closure->connection, owner_name, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, on_prompt_vanished, g_object_ref (task), g_object_unref); if (async_cancellable) { closure->cancelled_sig = g_cancellable_connect (async_cancellable, G_CALLBACK (on_prompt_cancelled), g_object_ref (task), g_object_unref); } g_dbus_proxy_call (proxy, "Prompt", g_variant_new ("(s)", window_id), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, closure->call_cancellable, on_prompt_prompted, g_object_ref (task)); g_clear_object (&task); g_free (owner_name); } /** * secret_prompt_perform_finish: * @self: a prompt * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Complete asynchronous operation to run a prompt and perform the prompting. * * Returns a variant result if the prompt was completed and not dismissed. The * type of result depends on the action the prompt is completing, and is * defined in the Secret Service DBus API specification. * * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred, * a variant result if the prompt was successful */ GVariant * secret_prompt_perform_finish (SecretPrompt *self, GAsyncResult *result, GError **error) { PerformClosure *closure; gchar *string; g_return_val_if_fail (SECRET_IS_PROMPT (self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (g_task_is_valid (result, self), NULL); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_prompt_perform, NULL); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return NULL; } closure = g_task_get_task_data (G_TASK (result)); if (closure->result == NULL) return NULL; if (closure->return_type != NULL && !g_variant_is_of_type (closure->result, closure->return_type)) { string = g_variant_type_dup_string (closure->return_type); g_warning ("received unexpected result type %s from Completed signal instead of expected %s", g_variant_get_type_string (closure->result), string); g_free (string); return NULL; } return g_variant_ref (closure->result); } 07070100000070000081A400000000000000000000000167D9F0D900000D9E000000000000000000000000000000000000002B00000000libsecret-0.21.7/libsecret/secret-prompt.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_PROMPT_H__ #define __SECRET_PROMPT_H__ #include #include "secret-types.h" G_BEGIN_DECLS #define SECRET_TYPE_PROMPT (secret_prompt_get_type ()) #define SECRET_PROMPT(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), SECRET_TYPE_PROMPT, SecretPrompt)) #define SECRET_PROMPT_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), SECRET_TYPE_PROMPT, SecretPromptClass)) #define SECRET_IS_PROMPT(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), SECRET_TYPE_PROMPT)) #define SECRET_IS_PROMPT_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), SECRET_TYPE_PROMPT)) #define SECRET_PROMPT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), SECRET_TYPE_PROMPT, SecretPromptClass)) typedef struct _SecretPrompt SecretPrompt; typedef struct _SecretPromptClass SecretPromptClass; typedef struct _SecretPromptPrivate SecretPromptPrivate; struct _SecretPrompt { GDBusProxy parent_instance; /*< private >*/ SecretPromptPrivate *pv; }; struct _SecretPromptClass { GDBusProxyClass parent_class; /*< private >*/ gpointer padding[8]; }; GType secret_prompt_get_type (void) G_GNUC_CONST; GVariant * secret_prompt_run (SecretPrompt *self, const gchar *window_id, GCancellable *cancellable, const GVariantType *return_type, GError **error); GVariant * secret_prompt_perform_sync (SecretPrompt *self, const gchar *window_id, GCancellable *cancellable, const GVariantType *return_type, GError **error); void secret_prompt_perform (SecretPrompt *self, const gchar *window_id, const GVariantType *return_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GVariant * secret_prompt_perform_finish (SecretPrompt *self, GAsyncResult *result, GError **error); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecretPrompt, g_object_unref) G_END_DECLS #endif /* __SECRET_PROMPT_H___ */ 07070100000071000081A400000000000000000000000167D9F0D900002214000000000000000000000000000000000000003000000000libsecret-0.21.7/libsecret/secret-retrievable.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #include "config.h" #include "secret-retrievable.h" #include "secret-private.h" /** * SecretRetrievable: * * A read-only view of a secret item in the Secret Service. * * #SecretRetrievable provides a read-only view of a secret item * stored in the Secret Service. * * Each item has a value, represented by a [struct@Value], which can be * retrieved by [method@Retrievable.retrieve_secret] and * [method@Retrievable.retrieve_secret_finish]. * * Stability: Stable * * Since: 0.19.0 */ /** * SecretRetrievableInterface: * @parent_iface: the parent interface * @retrieve_secret: implementation of [method@Retrievable.retrieve_secret], * required * @retrieve_secret_finish: implementation of * [method@Retrievable.retrieve_secret_finish], required * * The interface for #SecretRetrievable. * * Since: 0.19.0 */ G_DEFINE_INTERFACE (SecretRetrievable, secret_retrievable, G_TYPE_OBJECT); static void secret_retrievable_default_init (SecretRetrievableInterface *iface) { /** * SecretRetrievable:attributes: (type GLib.HashTable(utf8,utf8)) (transfer full) (attributes org.gtk.Property.get=secret_retrievable_get_attributes) * * The attributes set on this item. * * Attributes are used to locate an item. They are not guaranteed to be * stored or transferred securely. * * Since: 0.19.0 */ g_object_interface_install_property (iface, g_param_spec_boxed ("attributes", "Attributes", "Item attributes", G_TYPE_HASH_TABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * SecretRetrievable:label: (attributes org.gtk.Property.get=secret_retrievable_get_label) * * The human readable label for the item. * * Since: 0.19.0 */ g_object_interface_install_property (iface, g_param_spec_string ("label", "Label", "Item label", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * SecretRetrievable:created: (attributes org.gtk.Property.get=secret_retrievable_get_created) * * The date and time (in seconds since the UNIX epoch) that this * item was created. * * Since: 0.19.0 */ g_object_interface_install_property (iface, g_param_spec_uint64 ("created", "Created", "Item creation date", 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * SecretRetrievable:modified: (attributes org.gtk.Property.get=secret_retrievable_get_modified) * * The date and time (in seconds since the UNIX epoch) that this * item was last modified. * * Since: 0.19.0 */ g_object_interface_install_property (iface, g_param_spec_uint64 ("modified", "Modified", "Item modified date", 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } /** * secret_retrievable_retrieve_secret: * @self: a retrievable object * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback * * Retrieve the secret value of this object. * * Each retrievable object has a single secret which might be a * password or some other secret binary value. * * This function returns immediately and completes asynchronously. * * Since: 0.19.0 */ void secret_retrievable_retrieve_secret (SecretRetrievable *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretRetrievableInterface *iface; g_return_if_fail (SECRET_IS_RETRIEVABLE (self)); iface = SECRET_RETRIEVABLE_GET_IFACE (self); g_return_if_fail (iface->retrieve_secret != NULL); iface->retrieve_secret (self, cancellable, callback, user_data); } /** * secret_retrievable_retrieve_secret_finish: * @self: a retrievable object * @result: asynchronous result passed to callback * @error: location to place error on failure * * Complete asynchronous operation to retrieve the secret value of this object. * * Returns: (transfer full) (nullable): the secret value which should be * released with [method@Value.unref], or %NULL * * Since: 0.19.0 */ SecretValue * secret_retrievable_retrieve_secret_finish (SecretRetrievable *self, GAsyncResult *result, GError **error) { SecretRetrievableInterface *iface; g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), NULL); iface = SECRET_RETRIEVABLE_GET_IFACE (self); g_return_val_if_fail (iface->retrieve_secret_finish != NULL, NULL); return iface->retrieve_secret_finish (self, result, error); } /** * secret_retrievable_retrieve_secret_sync: * @self: a retrievable object * @cancellable: (nullable): optional cancellation object * @error: location to place error on failure * * Retrieve the secret value of this object synchronously. * * Each retrievable object has a single secret which might be a * password or some other secret binary value. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full) (nullable): the secret value which should be * released with [method@Value.unref], or %NULL * * Since: 0.19.0 */ SecretValue * secret_retrievable_retrieve_secret_sync (SecretRetrievable *self, GCancellable *cancellable, GError **error) { SecretSync *sync; SecretValue *value; g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_retrievable_retrieve_secret (self, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); value = secret_retrievable_retrieve_secret_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return value; } /** * secret_retrievable_get_attributes: (attributes org.gtk.Method.get_property=attributes) * @self: a retrievable object * * Get the attributes of this object. * * The attributes are a mapping of string keys to string values. * Attributes are used to search for items. Attributes are not stored * or transferred securely by the secret service. * * Do not modify the attribute returned by this method. * * Returns: (transfer full) (element-type utf8 utf8): a new reference * to the attributes, which should not be modified, and * released with [func@GLib.HashTable.unref] * * Since: 0.19.0 */ GHashTable * secret_retrievable_get_attributes (SecretRetrievable *self) { GHashTable *value; g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), NULL); g_object_get (G_OBJECT (self), "attributes", &value, NULL); return value; } /** * secret_retrievable_get_label: * @self: a retrievable object * * Get the label of this item. * * Returns: (transfer full): the label, which should be freed with [func@GLib.free] * * Since: 0.19.0 */ gchar * secret_retrievable_get_label (SecretRetrievable *self) { gchar *value; g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), NULL); g_object_get (G_OBJECT (self), "label", &value, NULL); return value; } /** * secret_retrievable_get_created: (attributes org.gtk.Method.get_property=created) * @self: a retrievable object * * Get the created date and time of the object. * * The return value is the number of seconds since the unix epoch, January 1st * 1970. * * Returns: the created date and time * * Since: 0.19.0 */ guint64 secret_retrievable_get_created (SecretRetrievable *self) { guint64 value; g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), 0); g_object_get (G_OBJECT (self), "created", &value, NULL); return value; } /** * secret_retrievable_get_modified: (attributes org.gtk.Method.get_property=modified) * @self: a retrievable object * * Get the modified date and time of the object. * * The return value is the number of seconds since the unix epoch, January 1st * 1970. * * Returns: the modified date and time * * Since: 0.19.0 */ guint64 secret_retrievable_get_modified (SecretRetrievable *self) { guint64 value; g_return_val_if_fail (SECRET_IS_RETRIEVABLE (self), 0); g_object_get (G_OBJECT (self), "modified", &value, NULL); return value; } 07070100000072000081A400000000000000000000000167D9F0D900000803000000000000000000000000000000000000003000000000libsecret-0.21.7/libsecret/secret-retrievable.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Red Hat, Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Daiki Ueno */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_RETRIEVABLE_H__ #define __SECRET_RETRIEVABLE_H__ #include #include "secret-value.h" G_BEGIN_DECLS #define SECRET_TYPE_RETRIEVABLE secret_retrievable_get_type () G_DECLARE_INTERFACE (SecretRetrievable, secret_retrievable, SECRET, RETRIEVABLE, GObject) struct _SecretRetrievableInterface { GTypeInterface parent_iface; void (*retrieve_secret) (SecretRetrievable *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretValue *(*retrieve_secret_finish) (SecretRetrievable *self, GAsyncResult *result, GError **error); }; void secret_retrievable_retrieve_secret (SecretRetrievable *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretValue *secret_retrievable_retrieve_secret_finish (SecretRetrievable *self, GAsyncResult *result, GError **error); SecretValue *secret_retrievable_retrieve_secret_sync (SecretRetrievable *self, GCancellable *cancellable, GError **error); GHashTable *secret_retrievable_get_attributes (SecretRetrievable *self); gchar *secret_retrievable_get_label (SecretRetrievable *self); guint64 secret_retrievable_get_created (SecretRetrievable *self); guint64 secret_retrievable_get_modified (SecretRetrievable *self); G_END_DECLS #endif /* __SECRET_RETRIEVABLE_H__ */ 07070100000073000081A400000000000000000000000167D9F0D900002E3C000000000000000000000000000000000000002B00000000libsecret-0.21.7/libsecret/secret-schema.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-password.h" #include "secret-private.h" #include "secret-value.h" #include "libsecret/secret-enum-types.h" #include "egg/egg-secure-memory.h" /** * SecretSchema: * @name: the dotted name of the schema * @flags: flags for the schema * @attributes: the attribute names and types of those attributes * * Represents a set of attributes that are stored with an item. * * These schemas are used for interoperability between various services storing * the same types of items. * * Each schema has a name like `org.gnome.keyring.NetworkPassword`, and defines a * set of attributes, and types (string, integer, boolean) for those attributes. * * Attributes are stored as strings in the Secret Service, and the attribute types * simply define standard ways to store integer and boolean values as strings. * Attributes are represented in libsecret via a [struct@GLib.HashTable] with * string keys and values. Even for values that defined as an integer or boolean in * the schema, the attribute values in the [struct@GLib.HashTable] are strings. * Boolean values are stored as the strings 'true' and 'false'. Integer values are * stored in decimal, with a preceding negative sign for negative integers. * * Schemas are handled entirely on the client side by this library. The name of the * schema is automatically stored as an attribute on the item. * * Normally when looking up passwords only those with matching schema names are * returned. If the schema @flags contain the `SECRET_SCHEMA_DONT_MATCH_NAME` flag, * then lookups will not check that the schema name matches that on the item, only * the schema's attributes are matched. This is useful when you are looking up * items that are not stored by the libsecret library. Other libraries such as * libgnome-keyring don't store the schema name. * * Additional schemas can be defined via the [struct@Schema] structure like this: * * ```c * // in a header: * * const SecretSchema * example_get_schema (void) G_GNUC_CONST; * * #define EXAMPLE_SCHEMA example_get_schema () * * * // in a .c file * * const SecretSchema * * example_get_schema (void) * { * static const SecretSchema the_schema = { * "org.example.Password", SECRET_SCHEMA_NONE, * { * { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, * { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, * { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, * { NULL, 0 }, * } * }; * return &the_schema; * } * ``` * * Stability: Stable */ /** * SecretSchemaFlags: * @SECRET_SCHEMA_NONE: no flags for the schema * @SECRET_SCHEMA_DONT_MATCH_NAME: don't match the schema name when looking up or * removing passwords * * Flags for a #SecretSchema definition. */ /** * SecretSchemaAttribute: * @name: name of the attribute * @type: the type of the attribute * * An attribute in a #SecretSchema. */ /** * SecretSchemaAttributeType: * @SECRET_SCHEMA_ATTRIBUTE_BOOLEAN: a boolean attribute, stored as 'true' or 'false' * @SECRET_SCHEMA_ATTRIBUTE_INTEGER: an integer attribute, stored as a decimal * @SECRET_SCHEMA_ATTRIBUTE_STRING: a utf-8 string attribute * * The type of an attribute in a [struct@SecretSchema]. * * Attributes are stored as strings in the Secret Service, and the attribute * types simply define standard ways to store integer and boolean values as * strings. */ static SecretSchemaAttribute * schema_attribute_copy (SecretSchemaAttribute *attribute) { SecretSchemaAttribute *copy; copy = g_new0 (SecretSchemaAttribute, 1); copy->name = g_strdup (attribute->name); copy->type = attribute->type; return copy; } static void schema_attribute_free (SecretSchemaAttribute *attribute) { g_free ((gchar *)attribute->name); g_free (attribute); } G_DEFINE_BOXED_TYPE (SecretSchemaAttribute, secret_schema_attribute, schema_attribute_copy, schema_attribute_free); /** * secret_schema_newv: (rename-to secret_schema_new) * @name: the dotted name of the schema * @flags: the flags for the schema * @attribute_names_and_types: (element-type utf8 Secret.SchemaAttributeType): the attribute names and types of those attributes * * Using this function is not normally necessary from C code. This is useful * for constructing #SecretSchema structures in bindings. * * A schema represents a set of attributes that are stored with an item. These * schemas are used for interoperability between various services storing the * same types of items. * * Each schema has an @name like `org.gnome.keyring.NetworkPassword`, and * defines a set of attributes names, and types (string, integer, boolean) for * those attributes. * * Each key in the @attributes table should be a attribute name strings, and * the values in the table should be integers from the [enum@SchemaAttributeType] * enumeration, representing the attribute type for each attribute name. * * Normally when looking up passwords only those with matching schema names are * returned. If the schema @flags contain the %SECRET_SCHEMA_DONT_MATCH_NAME flag, * then lookups will not check that the schema name matches that on the item, only * the schema's attributes are matched. This is useful when you are looking up items * that are not stored by the libsecret library. Other libraries such as libgnome-keyring * don't store the schema name. * * Returns: (transfer full): the new schema, which should be unreferenced with * [method@Schema.unref] when done */ SecretSchema * secret_schema_newv (const gchar *name, SecretSchemaFlags flags, GHashTable *attribute_names_and_types) { SecretSchema *schema; GHashTableIter iter; GEnumClass *enumc; gpointer value; gpointer key; gint type; gint ind = 0; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (attribute_names_and_types != NULL, NULL); schema = g_new0 (SecretSchema, 1); schema->name = g_strdup (name); schema->flags = flags; schema->reserved = 1; if (attribute_names_and_types) { g_hash_table_iter_init (&iter, attribute_names_and_types); while (g_hash_table_iter_next (&iter, &key, &value)) { if (ind >= G_N_ELEMENTS (schema->attributes)) { g_warning ("too many attributes for schema, max %d", (gint) G_N_ELEMENTS (schema->attributes)); break; } type = GPOINTER_TO_INT (value); enumc = G_ENUM_CLASS (g_type_class_ref (SECRET_TYPE_SCHEMA_ATTRIBUTE_TYPE)); if (!g_enum_get_value (enumc, type)) { g_warning ("invalid type for attribute %s", (gchar *)key); type = -1; } g_type_class_unref (enumc); if (type >= 0) { schema->attributes[ind].name = g_strdup (key); schema->attributes[ind].type = type; } ind++; } } return schema; } /** * secret_schema_new: (skip) * @name: the dotted name of the schema * @flags: the flags for the schema * @...: the attribute names and types, terminated with %NULL * * Using this function is not normally necessary from C code. * * A schema represents a set of attributes that are stored with an item. These * schemas are used for interoperability between various services storing the * same types of items. * * Each schema has an @name like `org.gnome.keyring.NetworkPassword`, and * defines a set of attributes names, and types (string, integer, boolean) for * those attributes. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) integers from the * [enum@SchemaAttributeType] enumeration, representing the attribute type for * each attribute name. The list of attributes should be terminated with a %NULL. * * Normally when looking up passwords only those with matching schema names are * returned. If the schema @flags contain the %SECRET_SCHEMA_DONT_MATCH_NAME flag, * then lookups will not check that the schema name matches that on the item, only * the schema's attributes are matched. This is useful when you are looking up items * that are not stored by the libsecret library. Other libraries such as libgnome-keyring * don't store the schema name. * * Returns: (transfer full): the new schema, which should be unreferenced with * [method@Schema.unref] when done */ SecretSchema * secret_schema_new (const gchar *name, SecretSchemaFlags flags, ...) { SecretSchemaAttributeType type; GHashTable *attributes; SecretSchema *schema; const gchar *attribute; va_list va; g_return_val_if_fail (name != NULL, NULL); va_start (va, flags); attributes = g_hash_table_new (g_str_hash, g_str_equal); while ((attribute = va_arg (va, const gchar *)) != NULL) { type = va_arg (va, SecretSchemaAttributeType); g_hash_table_insert (attributes, (gpointer *)attribute, GINT_TO_POINTER (type)); } schema = secret_schema_newv (name, flags, attributes); g_hash_table_unref (attributes); va_end (va); return schema; } /** * secret_schema_ref: * @schema: the schema to reference * * Adds a reference to the #SecretSchema. * * It is not normally necessary to call this function from C code, and is * mainly present for the sake of bindings. If the @schema was statically * allocated, then this function will copy the schema. * * Returns: (transfer full): the referenced schema, which should be later * unreferenced with [method@Schema.unref] */ SecretSchema * secret_schema_ref (SecretSchema *schema) { SecretSchema *result; gint i; g_return_val_if_fail (schema != NULL, NULL); /* If it's static, then copy it */ if (g_atomic_int_get (&schema->reserved) > 0) { g_atomic_int_inc (&schema->reserved); result = schema; } else { result = g_new0 (SecretSchema, 1); result->reserved = 1; result->name = g_strdup (schema->name); for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) { result->attributes[i].name = g_strdup (schema->attributes[i].name); result->attributes[i].type = schema->attributes[i].type; } } return result; } const SecretSchema * _secret_schema_ref_if_nonstatic (const SecretSchema *schema) { if (schema && g_atomic_int_get (&schema->reserved) > 0) secret_schema_ref ((SecretSchema *)schema); return schema; } /** * secret_schema_unref: * @schema: the schema to reference * * Releases a reference to the #SecretSchema. * * If the last reference is released then the schema will be freed. * * It is not normally necessary to call this function from C code, and is * mainly present for the sake of bindings. It is an error to call this for * a @schema that was statically allocated. */ void secret_schema_unref (SecretSchema *schema) { g_return_if_fail (schema != NULL); /* statically-allocated or invalid SecretSchema */ g_return_if_fail (g_atomic_int_get (&schema->reserved) > 0); if (g_atomic_int_dec_and_test (&schema->reserved)) { gint i; g_free ((gpointer)schema->name); for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) g_free ((gpointer)schema->attributes[i].name); g_free (schema); } } void _secret_schema_unref_if_nonstatic (const SecretSchema *schema) { if (schema && g_atomic_int_get (&schema->reserved) > 0) secret_schema_unref ((SecretSchema *)schema); } G_DEFINE_BOXED_TYPE (SecretSchema, secret_schema, secret_schema_ref, secret_schema_unref); 07070100000074000081A400000000000000000000000167D9F0D9000008C3000000000000000000000000000000000000002B00000000libsecret-0.21.7/libsecret/secret-schema.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_SCHEMA_H__ #define __SECRET_SCHEMA_H__ #include #include G_BEGIN_DECLS typedef enum { SECRET_SCHEMA_ATTRIBUTE_STRING = 0, SECRET_SCHEMA_ATTRIBUTE_INTEGER = 1, SECRET_SCHEMA_ATTRIBUTE_BOOLEAN = 2, } SecretSchemaAttributeType; typedef struct { const gchar* name; SecretSchemaAttributeType type; } SecretSchemaAttribute; typedef enum { SECRET_SCHEMA_NONE = 0, SECRET_SCHEMA_DONT_MATCH_NAME = 1 << 1 } SecretSchemaFlags; typedef struct { const gchar *name; SecretSchemaFlags flags; SecretSchemaAttribute attributes[32]; /* */ gint reserved; gpointer reserved1; gpointer reserved2; gpointer reserved3; gpointer reserved4; gpointer reserved5; gpointer reserved6; gpointer reserved7; } SecretSchema; GType secret_schema_get_type (void) G_GNUC_CONST; SecretSchema * secret_schema_new (const gchar *name, SecretSchemaFlags flags, ...) G_GNUC_NULL_TERMINATED; SecretSchema * secret_schema_newv (const gchar *name, SecretSchemaFlags flags, GHashTable *attribute_names_and_types); SecretSchema * secret_schema_ref (SecretSchema *schema); void secret_schema_unref (SecretSchema *schema); GType secret_schema_attribute_get_type (void) G_GNUC_CONST; G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecretSchema, g_object_unref) G_END_DECLS #endif /* __SECRET_SCHEMA_H___ */ 07070100000075000081A400000000000000000000000167D9F0D900000744000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/secret-schemas.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Stef Walter * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-schema.h" #include "secret-schemas.h" static const SecretSchema note_schema = { "org.gnome.keyring.Note", SECRET_SCHEMA_NONE, { { NULL, 0 }, } }; const SecretSchema * SECRET_SCHEMA_NOTE = ¬e_schema; static const SecretSchema network_schema = { "org.gnome.keyring.NetworkPassword", SECRET_SCHEMA_NONE, { { "user", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "domain", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "object", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "protocol", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "port", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "server", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "authtype", SECRET_SCHEMA_ATTRIBUTE_STRING }, { NULL, 0 }, } }; const SecretSchema * SECRET_SCHEMA_COMPAT_NETWORK = &network_schema; /** * secret_get_schema: * @type: type of schema to get * * Get a secret storage schema of the given @type. * * C code may access the schemas (such as %SECRET_SCHEMA_NOTE) directly, but * language bindings cannot, and must use this accessor. * * Returns: (transfer none): schema type * * Since: 0.18.6 */ const SecretSchema * secret_get_schema (SecretSchemaType type) { switch (type) { case SECRET_SCHEMA_TYPE_NOTE: return SECRET_SCHEMA_NOTE; case SECRET_SCHEMA_TYPE_COMPAT_NETWORK: return SECRET_SCHEMA_COMPAT_NETWORK; default: g_assert_not_reached (); } g_return_val_if_reached (NULL); } 07070100000076000081A400000000000000000000000167D9F0D900000D28000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/secret-schemas.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Stef Walter * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_SCHEMAS_H__ #define __SECRET_SCHEMAS_H__ #include #include "secret-schema.h" G_BEGIN_DECLS /* * A note or password stored manually by the user. */ extern const SecretSchema * SECRET_SCHEMA_NOTE; /* * This schema is here for compatibility with libgnome-keyring's network * password functions. */ extern const SecretSchema * SECRET_SCHEMA_COMPAT_NETWORK; /** * SecretSchemaType: * @SECRET_SCHEMA_TYPE_NOTE: Personal passwords * @SECRET_SCHEMA_TYPE_COMPAT_NETWORK: Network passwords from older * libgnome-keyring storage * * Different types of schemas for storing secrets, intended for use with * [func@get_schema]. * * ## @SECRET_SCHEMA_NOTE * * A predefined schema for personal passwords stored by the user in the * password manager. This schema has no attributes, and the items are not * meant to be used automatically by applications. * * When used to search for items using this schema, it will only match * items that have the same schema. Items stored via libgnome-keyring with the * `GNOME_KEYRING_ITEM_NOTE` item type will match. * * ## @SECRET_SCHEMA_COMPAT_NETWORK * * A predefined schema that is compatible with items stored via the * libgnome-keyring 'network password' functions. This is meant to be used by * applications migrating from libgnome-keyring which stored their secrets as * 'network passwords'. It is not recommended that new code use this schema. * * When used to search for items using this schema, it will only match * items that have the same schema. Items stored via libgnome-keyring with the * `GNOME_KEYRING_ITEM_NETWORK_PASSWORD` item type will match. * * The following attributes exist in the schema: * * ### Attributes: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
user:The user name (string).
domain:The login domain or realm (string).
object:The object or path (string).
protocol:The protocol (a string like 'http').
port:The network port (integer).
server:The hostname or server (string).
authtype:The authentication type (string).
* * Since: 0.18.6 */ typedef enum { SECRET_SCHEMA_TYPE_NOTE, SECRET_SCHEMA_TYPE_COMPAT_NETWORK, } SecretSchemaType; const SecretSchema *secret_get_schema (SecretSchemaType type); G_END_DECLS #endif /* __SECRET_SCHEMAS_H___ */ 07070100000077000081A400000000000000000000000167D9F0D90000F0E6000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/secret-service.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-backend.h" #include "secret-collection.h" #include "secret-dbus-generated.h" #include "secret-item.h" #include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "secret-types.h" #include "secret-value.h" #include "libsecret/secret-enum-types.h" #include "egg/egg-secure-memory.h" /** * SecretService: * * A proxy object representing the Secret Service. * * A #SecretService object either represents an implementation of the * [`org.freedesktop.Secret`](https://specifications.freedesktop.org/secret-service/latest/) * D-Bus service or a file that is encrypted using a master secret that was * provided by the * [secret portal](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Secret.html). * * Normally a single #SecretService object can be shared between multiple * callers. The [func@Service.get] method is used to access this #SecretService * object. If a new independent #SecretService object is required, use * [func@Service.open]. * * In order to securely transfer secrets to the Sercret Service, a session * is established. This session can be established while initializing a * #SecretService object by passing the %SECRET_SERVICE_OPEN_SESSION flag * to the [func@Service.get] or [func@Service.open] functions. In order to * establish a session on an already existing #SecretService, use the * [method@Service.ensure_session] function. * * To search for items, use the [method@Service.search] method. * * Multiple collections can exist in the Secret Service, each of which contains * secret items. In order to instantiate [class@Collection] objects which * represent those collections while initializing a #SecretService then pass * the %SECRET_SERVICE_LOAD_COLLECTIONS flag to the [func@Service.get] or * [func@Service.open] functions. In order to establish a session on an already * existing #SecretService, use the [method@Service.load_collections] function. * To access the list of collections use [method@Service.get_collections]. * * Certain actions on the Secret Service require user prompting to complete, * such as creating a collection, or unlocking a collection. When such a prompt * is necessary, then a [class@Prompt] object is created by this library, and * passed to the [method@Service.prompt] method. In this way it is handled * automatically. * * In order to customize prompt handling, override the * [vfunc@Service.prompt_async] and [vfunc@Service.prompt_finish] virtual * methods of the #SecretService class. * * Stability: Stable */ /** * SecretServiceClass: * @parent_class: the parent class * @collection_gtype: the [alias@GObject.Type] of the [class@Collection] objects * instantiated by the #SecretService proxy * @item_gtype: the [alias@GObject.Type] of the [class@Item] objects * instantiated by the #SecretService proxy * @prompt_async: called to perform asynchronous prompting when necessary * @prompt_finish: called to complete an asynchronous prompt operation * @prompt_sync: called to perform synchronous prompting when necessary * @get_collection_gtype: called to get the GObject type for collections * instantiated by the #SecretService proxy * @get_item_gtype: called to get the GObject type for collections * instantiated by the #SecretService proxy * * The class for #SecretService. */ /** * SecretServiceFlags: * @SECRET_SERVICE_NONE: no flags for initializing the #SecretService * @SECRET_SERVICE_OPEN_SESSION: establish a session for transfer of secrets * while initializing the #SecretService * @SECRET_SERVICE_LOAD_COLLECTIONS: load collections while initializing the * #SecretService * * Flags which determine which parts of the #SecretService proxy are initialized * during a [func@Service.get] or [func@Service.open] operation. */ EGG_SECURE_DEFINE_GLIB_GLOBALS (); GQuark _secret_error_quark = 0; enum { PROP_0, PROP_FLAGS, PROP_COLLECTIONS }; struct _SecretServicePrivate { /* No change between construct and finalize */ GCancellable *cancellable; SecretServiceFlags init_flags; /* Locked by mutex */ GMutex mutex; gpointer session; GHashTable *collections; }; G_LOCK_DEFINE (service_instance); static gpointer service_instance = NULL; static guint service_watch = 0; static GInitableIface *secret_service_initable_parent_iface = NULL; static GAsyncInitableIface *secret_service_async_initable_parent_iface = NULL; static SecretBackendInterface *secret_service_backend_parent_iface = NULL; static void secret_service_initable_iface (GInitableIface *iface); static void secret_service_async_initable_iface (GAsyncInitableIface *iface); static void secret_service_backend_iface (SecretBackendInterface *iface); G_DEFINE_TYPE_WITH_CODE (SecretService, secret_service, G_TYPE_DBUS_PROXY, G_ADD_PRIVATE (SecretService) G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_service_initable_iface); G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_service_async_initable_iface); G_IMPLEMENT_INTERFACE (SECRET_TYPE_BACKEND, secret_service_backend_iface); _secret_backend_ensure_extension_point (); g_io_extension_point_implement (SECRET_BACKEND_EXTENSION_POINT_NAME, g_define_type_id, "service", 0) ); static SecretService * service_get_instance (void) { SecretService *instance = NULL; G_LOCK (service_instance); if (service_instance != NULL) instance = g_object_ref (service_instance); G_UNLOCK (service_instance); return instance; } static gboolean service_uncache_instance (SecretService *which) { SecretService *instance = NULL; guint watch = 0; gboolean matched = FALSE; G_LOCK (service_instance); if (which == NULL || service_instance == which) { instance = service_instance; service_instance = NULL; watch = service_watch; service_watch = 0; matched = TRUE; } G_UNLOCK (service_instance); if (instance != NULL) g_object_unref (instance); if (watch != 0) g_bus_unwatch_name (watch); _secret_backend_uncache_instance (); return matched; } static void on_service_instance_vanished (GDBusConnection *connection, const gchar *name, gpointer user_data) { if (!service_uncache_instance (user_data)) { g_warning ("Global default SecretService instance out of sync " "with the watch for its DBus name"); } } static void service_cache_instance (SecretService *instance) { GDBusProxy *proxy; guint watch; g_object_ref (instance); proxy = G_DBUS_PROXY (instance); watch = g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (proxy), g_dbus_proxy_get_name (proxy), G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, on_service_instance_vanished, instance, NULL); G_LOCK (service_instance); if (service_instance == NULL) { service_instance = instance; instance = NULL; service_watch = watch; watch = 0; } G_UNLOCK (service_instance); if (instance != NULL) g_object_unref (instance); if (watch != 0) g_bus_unwatch_name (watch); } static void secret_service_init (SecretService *self) { self->pv = secret_service_get_instance_private (self); g_mutex_init (&self->pv->mutex); self->pv->cancellable = g_cancellable_new (); } static void secret_service_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { SecretService *self = SECRET_SERVICE (obj); switch (prop_id) { case PROP_FLAGS: g_value_set_flags (value, secret_service_get_flags (self)); break; case PROP_COLLECTIONS: g_value_take_boxed (value, secret_service_get_collections (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void secret_service_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { SecretService *self = SECRET_SERVICE (obj); switch (prop_id) { case PROP_FLAGS: self->pv->init_flags = g_value_get_flags (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void secret_service_dispose (GObject *obj) { SecretService *self = SECRET_SERVICE (obj); g_cancellable_cancel (self->pv->cancellable); G_OBJECT_CLASS (secret_service_parent_class)->dispose (obj); } static void secret_service_finalize (GObject *obj) { SecretService *self = SECRET_SERVICE (obj); _secret_session_free (self->pv->session); if (self->pv->collections) g_hash_table_destroy (self->pv->collections); g_clear_object (&self->pv->cancellable); g_mutex_clear (&self->pv->mutex); G_OBJECT_CLASS (secret_service_parent_class)->finalize (obj); } static GVariant * secret_service_real_prompt_sync (SecretService *self, SecretPrompt *prompt, GCancellable *cancellable, const GVariantType *return_type, GError **error) { return secret_prompt_perform_sync (prompt, NULL, cancellable, return_type, error); } static void on_real_prompt_completed (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GError *error = NULL; GVariant *retval; retval = secret_prompt_perform_finish (SECRET_PROMPT (source), result, &error); if (retval != NULL) g_task_return_pointer (task, g_steal_pointer (&retval), (GDestroyNotify) g_variant_unref); else g_task_return_error (task, g_steal_pointer (&error)); g_object_unref (task); } static void secret_service_real_prompt_async (SecretService *self, SecretPrompt *prompt, const GVariantType *return_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_real_prompt_async); secret_prompt_perform (prompt, 0, return_type, cancellable, on_real_prompt_completed, g_object_ref (task)); g_object_unref (task); } static GVariant * secret_service_real_prompt_finish (SecretService *self, GAsyncResult *result, GError **error) { GVariant *retval; g_return_val_if_fail (g_task_is_valid (result, self), NULL); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_service_real_prompt_async, NULL); retval = g_task_propagate_pointer (G_TASK (result), error); if (!retval) { _secret_util_strip_remote_error (error); return NULL; } return retval; } static void handle_property_changed (SecretService *self, const gchar *property_name, GVariant *value) { gboolean perform; g_variant_ref_sink (value); if (g_str_equal (property_name, "Collections")) { g_mutex_lock (&self->pv->mutex); perform = self->pv->collections != NULL; g_mutex_unlock (&self->pv->mutex); if (perform) secret_service_load_collections (self, self->pv->cancellable, NULL, NULL); } g_variant_unref (value); } static void secret_service_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, const gchar* const *invalidated_properties) { SecretService *self = SECRET_SERVICE (proxy); gchar *property_name; GVariantIter iter; GVariant *value; g_object_freeze_notify (G_OBJECT (self)); g_variant_iter_init (&iter, changed_properties); while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value)) handle_property_changed (self, property_name, value); g_object_thaw_notify (G_OBJECT (self)); } static void secret_service_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters) { SecretService *self = SECRET_SERVICE (proxy); SecretCollection *collection; const gchar *collection_path; GVariantBuilder builder; gboolean found = FALSE; GVariantIter iter; GVariant *value; GVariant *paths; GVariant *path; /* * Remember that these signals come from a time before PropertiesChanged. * We support them because they're in the spec, and ksecretservice uses them. */ paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections"); g_return_if_fail (paths != NULL); /* A new collection was added, add it to the Collections property */ if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CREATED)) { g_variant_get (parameters, "(@o)", &value); g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao")); g_variant_iter_init (&iter, paths); while ((path = g_variant_iter_next_value (&iter)) != NULL) { if (g_variant_equal (path, value)) { found = TRUE; break; } g_variant_builder_add_value (&builder, path); g_variant_unref (path); } if (!found) { g_variant_builder_add_value (&builder, value); handle_property_changed (self, "Collections", g_variant_builder_end (&builder)); } g_variant_builder_clear (&builder); g_variant_unref (value); /* A collection was deleted, remove it from the Collections property */ } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_DELETED)) { g_variant_get (parameters, "(@o)", &value); g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao")); g_variant_iter_init (&iter, paths); while ((path = g_variant_iter_next_value (&iter)) != NULL) { if (g_variant_equal (path, value)) found = TRUE; else g_variant_builder_add_value (&builder, path); g_variant_unref (path); } if (found) handle_property_changed (self, "Collections", g_variant_builder_end (&builder)); g_variant_unref (value); /* The collection changed, update it */ } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CHANGED)) { g_variant_get (parameters, "(&o)", &collection_path); g_mutex_lock (&self->pv->mutex); if (self->pv->collections) collection = g_hash_table_lookup (self->pv->collections, collection_path); else collection = NULL; if (collection) g_object_ref (collection); g_mutex_unlock (&self->pv->mutex); if (collection) { secret_collection_refresh (collection); g_object_unref (collection); } } g_variant_unref (paths); } static GType secret_service_real_get_collection_gtype (SecretService *self) { SecretServiceClass *klass; klass = SECRET_SERVICE_GET_CLASS (self); return klass->collection_gtype; } static GType secret_service_real_get_item_gtype (SecretService *self) { SecretServiceClass *klass; klass = SECRET_SERVICE_GET_CLASS (self); return klass->item_gtype; } static const gchar * get_default_bus_name (void) { const gchar *bus_name; bus_name = g_getenv ("SECRET_SERVICE_BUS_NAME"); if (bus_name == NULL) bus_name = SECRET_SERVICE_BUS_NAME; return bus_name; } static GObject * secret_service_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GObject *object; object = G_OBJECT_CLASS (secret_service_parent_class)-> constructor (type, n_construct_properties, construct_properties); g_object_set (object, "g-flags", G_DBUS_PROXY_FLAGS_NONE, "g-interface-info", _secret_gen_service_interface_info (), "g-name", get_default_bus_name (), "g-bus-type", G_BUS_TYPE_SESSION, "g-object-path", SECRET_SERVICE_PATH, "g-interface-name", SECRET_SERVICE_INTERFACE, NULL); return object; } static void secret_service_class_init (SecretServiceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass); object_class->get_property = secret_service_get_property; object_class->set_property = secret_service_set_property; object_class->dispose = secret_service_dispose; object_class->finalize = secret_service_finalize; object_class->constructor = secret_service_constructor; proxy_class->g_properties_changed = secret_service_properties_changed; proxy_class->g_signal = secret_service_signal; klass->prompt_sync = secret_service_real_prompt_sync; klass->prompt_async = secret_service_real_prompt_async; klass->prompt_finish = secret_service_real_prompt_finish; klass->item_gtype = SECRET_TYPE_ITEM; klass->collection_gtype = SECRET_TYPE_COLLECTION; klass->get_item_gtype = secret_service_real_get_item_gtype; klass->get_collection_gtype = secret_service_real_get_collection_gtype; /** * SecretService:flags: * * A set of flags describing which parts of the secret service have * been initialized. */ g_object_class_override_property (object_class, PROP_FLAGS, "flags"); /** * SecretService:collections: (attributes org.gtk.Property.get=secret_service_get_collections) * * A list of [class@Collection] objects representing the collections in * the Secret Service. * * This list may be %NULL if the collections have not been loaded. * * To load the collections, specify the %SECRET_SERVICE_LOAD_COLLECTIONS * initialization flag when calling the [func@Service.get] or * [func@Service.open] functions. Or call the [method@Service.load_collections] * method. */ g_object_class_install_property (object_class, PROP_COLLECTIONS, g_param_spec_boxed ("collections", "Collections", "Secret Service Collections", _secret_list_get_type (), G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /* Initialize this error domain, registers dbus errors */ _secret_error_quark = secret_error_get_quark (); } typedef struct { SecretServiceFlags flags; } InitClosure; static void init_closure_free (gpointer data) { InitClosure *closure = data; g_free (closure); } static gboolean service_ensure_for_flags_sync (SecretService *self, SecretServiceFlags flags, GCancellable *cancellable, GError **error) { if (flags & SECRET_SERVICE_OPEN_SESSION) if (!secret_service_ensure_session_sync (self, cancellable, error)) return FALSE; if (flags & SECRET_SERVICE_LOAD_COLLECTIONS) if (!secret_service_load_collections_sync (self, cancellable, error)) return FALSE; return TRUE; } static void on_load_collections (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretService *self = SECRET_SERVICE (source); GError *error = NULL; if (!secret_service_load_collections_finish (self, result, &error)) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_boolean (task, TRUE); g_object_unref (task); } static void on_ensure_session (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); InitClosure *closure = g_task_get_task_data (task); SecretService *self = SECRET_SERVICE (source); GError *error = NULL; if (!secret_service_ensure_session_finish (self, result, &error)) { g_task_return_error (task, g_steal_pointer (&error)); } else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS) { secret_service_load_collections (self, g_task_get_cancellable (task), on_load_collections, g_object_ref (task)); } else { g_task_return_boolean (task, TRUE); } g_object_unref (task); } static void service_ensure_for_flags_async (SecretService *self, SecretServiceFlags flags, GTask *task) { InitClosure *closure = g_task_get_task_data (task); closure->flags = flags; if (closure->flags & SECRET_SERVICE_OPEN_SESSION) secret_service_ensure_session (self, g_task_get_cancellable (task), on_ensure_session, g_object_ref (task)); else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS) secret_service_load_collections (self, g_task_get_cancellable (task), on_load_collections, g_object_ref (task)); else g_task_return_boolean (task, TRUE); } static gboolean secret_service_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { SecretService *self; if (!secret_service_initable_parent_iface->init (initable, cancellable, error)) return FALSE; self = SECRET_SERVICE (initable); return service_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error); } static void secret_service_initable_iface (GInitableIface *iface) { secret_service_initable_parent_iface = g_type_interface_peek_parent (iface); iface->init = secret_service_initable_init; } static void secret_service_async_initable_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); typedef struct { GAsyncReadyCallback callback; gpointer user_data; } InitBaseClosure; static void on_init_base (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *base_task = G_TASK (user_data); InitBaseClosure *base = g_task_get_task_data (base_task); GCancellable *cancellable = g_task_get_cancellable (base_task); GTask *task; InitClosure *init; SecretService *self = SECRET_SERVICE (source); GError *error = NULL; task = g_task_new (source, cancellable, base->callback, base->user_data); g_task_set_source_tag (task, secret_service_async_initable_init_async); init = g_new0 (InitClosure, 1); g_task_set_task_data (task, init, init_closure_free); g_clear_object (&base_task); if (!secret_service_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self), result, &error)) { g_task_return_error (task, g_steal_pointer (&error)); } else { service_ensure_for_flags_async (self, self->pv->init_flags, task); } g_object_unref (task); } static void secret_service_async_initable_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; InitBaseClosure *base; task = g_task_new (initable, cancellable, NULL, NULL); g_task_set_source_tag (task, secret_service_async_initable_init_async); base = g_new0 (InitBaseClosure, 1); base->callback = callback; base->user_data = user_data; g_task_set_task_data (task, base, g_free); secret_service_async_initable_parent_iface->init_async (initable, io_priority, cancellable, on_init_base, g_object_ref (task)); g_object_unref (task); } static gboolean secret_service_async_initable_init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, initable), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } static void secret_service_async_initable_iface (GAsyncInitableIface *iface) { secret_service_async_initable_parent_iface = g_type_interface_peek_parent (iface); iface->init_async = secret_service_async_initable_init_async; iface->init_finish = secret_service_async_initable_init_finish; } static void secret_service_real_ensure_for_flags (SecretBackend *self, SecretBackendFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; InitClosure *closure; g_return_if_fail (SECRET_IS_SERVICE (self)); task = g_task_new (self, cancellable, callback, user_data); closure = g_new0 (InitClosure, 1); g_task_set_task_data (task, closure, init_closure_free); service_ensure_for_flags_async (SECRET_SERVICE (self), flags, task); g_object_unref (task); } static gboolean secret_service_real_ensure_for_flags_finish (SecretBackend *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, self), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } static void secret_service_real_store (SecretBackend *self, const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_SERVICE (self)); secret_service_store (SECRET_SERVICE (self), schema, attributes, collection, label, value, cancellable, callback, user_data); } static gboolean secret_service_real_store_finish (SecretBackend *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); return secret_service_store_finish (SECRET_SERVICE (self), result, error); } static void secret_service_real_lookup (SecretBackend *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_SERVICE (self)); secret_service_lookup (SECRET_SERVICE (self), schema, attributes, cancellable, callback, user_data); } static SecretValue * secret_service_real_lookup_finish (SecretBackend *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); return secret_service_lookup_finish (SECRET_SERVICE (self), result, error); } static void secret_service_real_clear (SecretBackend *self, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_SERVICE (self)); secret_service_clear (SECRET_SERVICE (self), schema, attributes, cancellable, callback, user_data); } static gboolean secret_service_real_clear_finish (SecretBackend *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); return secret_service_clear_finish (SECRET_SERVICE (self), result, error); } static void secret_service_real_search (SecretBackend *self, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (SECRET_IS_SERVICE (self)); secret_service_search (SECRET_SERVICE (self), schema, attributes, flags, cancellable, callback, user_data); } static GList * secret_service_real_search_finish (SecretBackend *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); return secret_service_search_finish (SECRET_SERVICE (self), result, error); } static void secret_service_backend_iface (SecretBackendInterface *iface) { secret_service_backend_parent_iface = g_type_interface_peek_parent (iface); iface->ensure_for_flags = secret_service_real_ensure_for_flags; iface->ensure_for_flags_finish = secret_service_real_ensure_for_flags_finish; iface->store = secret_service_real_store; iface->store_finish = secret_service_real_store_finish; iface->lookup = secret_service_real_lookup; iface->lookup_finish = secret_service_real_lookup_finish; iface->clear = secret_service_real_clear; iface->clear_finish = secret_service_real_clear_finish; iface->search = secret_service_real_search; iface->search_finish = secret_service_real_search_finish; } /** * secret_service_get: * @flags: flags for which service functionality to ensure is initialized * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Get a #SecretService proxy for the Secret Service. * * If such a proxy object already exists, then the same proxy is returned. * * If @flags contains any flags of which parts of the secret service to * ensure are initialized, then those will be initialized before completing. * * This method will return immediately and complete asynchronously. */ void secret_service_get (SecretServiceFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretService *service = NULL; GTask *task; InitClosure *closure; service = service_get_instance (); /* Create a whole new service */ if (service == NULL) { g_async_initable_new_async (SECRET_TYPE_SERVICE, G_PRIORITY_DEFAULT, cancellable, callback, user_data, "flags", flags, NULL); /* Just have to ensure that the service matches flags */ } else { task = g_task_new (service, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_get); closure = g_new0 (InitClosure, 1); closure->flags = flags; g_task_set_task_data (task, closure, init_closure_free); service_ensure_for_flags_async (service, flags, task); g_object_unref (service); g_object_unref (task); } } /** * secret_service_get_finish: * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Complete an asynchronous operation to get a #SecretService proxy for the * Secret Service. * * Returns: (transfer full): a new reference to a #SecretService proxy, which * should be released with [method@GObject.Object.unref]. */ SecretService * secret_service_get_finish (GAsyncResult *result, GError **error) { GTask *task; GObject *service = NULL; GObject *source_object; g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); task = G_TASK (result); source_object = g_task_get_source_object (task); g_return_val_if_fail (g_task_is_valid (result, source_object), NULL); /* Just ensuring that the service matches flags */ if (g_task_get_source_tag (task) == secret_service_get) { if (g_task_had_error (task)) { g_task_propagate_pointer (task, error); _secret_util_strip_remote_error (error); } else { service = g_object_ref (source_object); } /* Creating a whole new service */ } else { service = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error); if (service) service_cache_instance (SECRET_SERVICE (service)); } if (service == NULL) return NULL; return SECRET_SERVICE (service); } /** * secret_service_get_sync: * @flags: flags for which service functionality to ensure is initialized * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Get a #SecretService proxy for the Secret Service. * * If such a proxy object already exists, then the same proxy is returned. * * If @flags contains any flags of which parts of the secret service to * ensure are initialized, then those will be initialized before returning. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): a new reference to a #SecretService proxy, which * should be released with [method@GObject.Object.unref]. */ SecretService * secret_service_get_sync (SecretServiceFlags flags, GCancellable *cancellable, GError **error) { SecretService *service = NULL; service = service_get_instance (); if (service == NULL) { service = g_initable_new (SECRET_TYPE_SERVICE, cancellable, error, "flags", flags, NULL); if (service != NULL) service_cache_instance (service); } else { if (!service_ensure_for_flags_sync (service, flags, cancellable, error)) { g_object_unref (service); return NULL; } } return service; } /** * secret_service_disconnect: * * Disconnect the default #SecretService proxy returned by [func@Service.get] * and [func@Service.get_sync]. * * It is not necessary to call this function, but you may choose to do so at * program exit. It is useful for testing that memory is not leaked. * * This function is safe to call at any time. But if other objects in this * library are still referenced, then this will not result in all memory * being freed. */ void secret_service_disconnect (void) { service_uncache_instance (NULL); } /** * secret_service_open: * @service_gtype: the GType of the new secret service * @service_bus_name: (nullable): the D-Bus service name of the secret service * @flags: flags for which service functionality to ensure is initialized * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Create a new #SecretService proxy for the Secret Service. * * This function is rarely used, see [func@Service.get] instead. * * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the type * of a derived class. * * If @flags contains any flags of which parts of the secret service to * ensure are initialized, then those will be initialized before returning. * * If @service_bus_name is %NULL then the default is used. * * This method will return immediately and complete asynchronously. */ void secret_service_open (GType service_gtype, const gchar *service_bus_name, SecretServiceFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE)); g_async_initable_new_async (service_gtype, G_PRIORITY_DEFAULT, cancellable, callback, user_data, "flags", flags, NULL); } /** * secret_service_open_finish: * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Complete an asynchronous operation to create a new #SecretService proxy for * the Secret Service. * * Returns: (transfer full): a new reference to a #SecretService proxy, which * should be released with [method@GObject.Object.unref]. */ SecretService * secret_service_open_finish (GAsyncResult *result, GError **error) { GObject *source_object; GObject *object; g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); source_object = g_async_result_get_source_object (result); object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error); g_object_unref (source_object); if (object == NULL) return NULL; return SECRET_SERVICE (object); } /** * secret_service_open_sync: * @service_gtype: the GType of the new secret service * @service_bus_name: (nullable): the D-Bus service name of the secret service * @flags: flags for which service functionality to ensure is initialized * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Create a new #SecretService proxy for the Secret Service. * * This function is rarely used, see [func@Service.get_sync] instead. * * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the * type of a derived class. * * If @flags contains any flags of which parts of the secret service to * ensure are initialized, then those will be initialized before returning. * * If @service_bus_name is %NULL then the default is used. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: (transfer full): a new reference to a #SecretService proxy, which * should be released with [method@GObject.Object.unref]. */ SecretService * secret_service_open_sync (GType service_gtype, const gchar *service_bus_name, SecretServiceFlags flags, GCancellable *cancellable, GError **error) { g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE), NULL); return g_initable_new (service_gtype, cancellable, error, "flags", flags, NULL); } /** * secret_service_get_flags: * @self: the secret service proxy * * Get the flags representing what features of the #SecretService proxy * have been initialized. * * Use [method@Service.ensure_session] or [method@Service.load_collections] * to initialize further features and change the flags. * * Returns: the flags for features initialized */ SecretServiceFlags secret_service_get_flags (SecretService *self) { SecretServiceFlags flags = 0; g_return_val_if_fail (SECRET_IS_SERVICE (self), SECRET_SERVICE_NONE); g_mutex_lock (&self->pv->mutex); if (self->pv->session) flags |= SECRET_SERVICE_OPEN_SESSION; if (self->pv->collections) flags |= SECRET_SERVICE_LOAD_COLLECTIONS; g_mutex_unlock (&self->pv->mutex); return flags; } /** * secret_service_get_collections: (attributes org.gtk.Method.get_property=collections) * @self: the secret service proxy * * Get a list of [class@Collection] objects representing all the collections * in the secret service. * * If the %SECRET_SERVICE_LOAD_COLLECTIONS flag was not specified when * initializing #SecretService proxy object, then this method will return * %NULL. Use [method@Service.load_collections] to load the collections. * * Returns: (transfer full) (element-type Secret.Collection) (nullable): a * list of the collections in the secret service */ GList * secret_service_get_collections (SecretService *self) { GList *l, *collections; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_mutex_lock (&self->pv->mutex); if (self->pv->collections == NULL) { collections = NULL; } else { collections = g_hash_table_get_values (self->pv->collections); for (l = collections; l != NULL; l = g_list_next (l)) g_object_ref (l->data); } g_mutex_unlock (&self->pv->mutex); return collections; } SecretItem * _secret_service_find_item_instance (SecretService *self, const gchar *item_path) { SecretCollection *collection = NULL; gchar *collection_path; SecretItem *item; collection_path = _secret_util_parent_path (item_path); collection = _secret_service_find_collection_instance (self, collection_path); g_free (collection_path); if (collection == NULL) return NULL; item = _secret_collection_find_item_instance (collection, item_path); g_object_unref (collection); return item; } SecretCollection * _secret_service_find_collection_instance (SecretService *self, const gchar *collection_path) { SecretCollection *collection = NULL; g_mutex_lock (&self->pv->mutex); if (self->pv->collections) { collection = g_hash_table_lookup (self->pv->collections, collection_path); if (collection != NULL) g_object_ref (collection); } g_mutex_unlock (&self->pv->mutex); return collection; } SecretSession * _secret_service_get_session (SecretService *self) { SecretSession *session; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_mutex_lock (&self->pv->mutex); session = self->pv->session; g_mutex_unlock (&self->pv->mutex); return session; } void _secret_service_take_session (SecretService *self, SecretSession *session) { g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (session != NULL); g_mutex_lock (&self->pv->mutex); if (self->pv->session == NULL) self->pv->session = session; else _secret_session_free (session); g_mutex_unlock (&self->pv->mutex); } /** * secret_service_get_session_algorithms: * @self: the secret service proxy * * Get the set of algorithms being used to transfer secrets between this * secret service proxy and the Secret Service itself. * * This will be %NULL if no session has been established. Use * [method@Service.ensure_session] to establish a session. * * Returns: (nullable): a string representing the algorithms for transferring * secrets */ const gchar * secret_service_get_session_algorithms (SecretService *self) { SecretSession *session; const gchar *algorithms; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_mutex_lock (&self->pv->mutex); session = self->pv->session; algorithms = session ? _secret_session_get_algorithms (session) : NULL; g_mutex_unlock (&self->pv->mutex); /* Session never changes once established, so can return const */ return algorithms; } /** * secret_service_get_session_dbus_path: * @self: the secret service proxy * * Get the D-Bus object path of the session object being used to transfer * secrets between this secret service proxy and the Secret Service itself. * * This will be %NULL if no session has been established. Use * [method@Service.ensure_session] to establish a session. * * Returns: (nullable): a string representing the D-Bus object path of the * session */ const gchar * secret_service_get_session_dbus_path (SecretService *self) { SecretSession *session; const gchar *path; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_mutex_lock (&self->pv->mutex); session = self->pv->session; path = session ? _secret_session_get_path (session) : NULL; g_mutex_unlock (&self->pv->mutex); /* Session never changes once established, so can return const */ return path; } /** * secret_service_ensure_session: * @self: the secret service * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Ensure that the #SecretService proxy has established a session with the * Secret Service. * * This session is used to transfer secrets. * * It is not normally necessary to call this method, as the session is * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION * to [func@Service.get] in order to ensure that a session has been established * by the time you get the #SecretService proxy. * * This method will return immediately and complete asynchronously. */ void secret_service_ensure_session (SecretService *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; SecretSession *session; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_mutex_lock (&self->pv->mutex); session = self->pv->session; g_mutex_unlock (&self->pv->mutex); if (session == NULL) { _secret_session_open (self, cancellable, callback, user_data); } else { task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_ensure_session); g_task_return_boolean (task, TRUE); g_object_unref (task); } } /** * secret_service_ensure_session_finish: * @self: the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Finish an asynchronous operation to ensure that the #SecretService proxy * has established a session with the Secret Service. * * Returns: whether a session is established or not */ gboolean secret_service_ensure_session_finish (SecretService *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_task_is_valid (result, self), FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } g_return_val_if_fail (self->pv->session != NULL, FALSE); return TRUE; } /** * secret_service_ensure_session_sync: * @self: the secret service * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Ensure that the #SecretService proxy has established a session with the * Secret Service. * * This session is used to transfer secrets. * * It is not normally necessary to call this method, as the session is * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION * to [func@Service.get_sync] in order to ensure that a session has been * established by the time you get the #SecretService proxy. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether a session is established or not */ gboolean secret_service_ensure_session_sync (SecretService *self, GCancellable *cancellable, GError **error) { SecretSync *sync; gboolean ret; g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); secret_service_ensure_session (self, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); ret = secret_service_ensure_session_finish (self, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); return ret; } static SecretCollection * service_lookup_collection (SecretService *self, const gchar *path) { SecretCollection *collection = NULL; g_mutex_lock (&self->pv->mutex); if (self->pv->collections) { collection = g_hash_table_lookup (self->pv->collections, path); if (collection != NULL) g_object_ref (collection); } g_mutex_unlock (&self->pv->mutex); return collection; } static void service_update_collections (SecretService *self, GHashTable *collections) { GHashTable *previous; g_hash_table_ref (collections); g_mutex_lock (&self->pv->mutex); previous = self->pv->collections; self->pv->collections = collections; g_mutex_unlock (&self->pv->mutex); if (previous != NULL) g_hash_table_unref (previous); g_object_notify (G_OBJECT (self), "collections"); } typedef struct { GHashTable *collections; gint collections_loading; } EnsureClosure; static GHashTable * collections_table_new (void) { return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } static void ensure_closure_free (gpointer data) { EnsureClosure *closure = data; g_hash_table_unref (closure->collections); g_free (closure); } static void on_ensure_collection (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data)); EnsureClosure *closure = g_task_get_task_data (task); SecretCollection *collection; const gchar *path; GError *error = NULL; closure->collections_loading--; collection = secret_collection_new_for_dbus_path_finish (result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else if (collection != NULL) { path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)); g_hash_table_insert (closure->collections, g_strdup (path), collection); if (closure->collections_loading == 0) { service_update_collections (self, closure->collections); g_task_return_boolean (task, TRUE); } } g_object_unref (self); g_object_unref (task); } /** * secret_service_load_collections: * @self: the secret service * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Ensure that the #SecretService proxy has loaded all the collections present * in the Secret Service. * * This affects the result of [method@Service.get_collections]. * * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to * [func@Service.get_sync] in order to ensure that the collections have been * loaded by the time you get the #SecretService proxy. * * This method will return immediately and complete asynchronously. */ void secret_service_load_collections (SecretService *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { EnsureClosure *closure; SecretCollection *collection; GTask *task; const gchar *path; GVariant *paths; GVariantIter iter; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections"); g_return_if_fail (paths != NULL); task = g_task_new (self, cancellable, callback, user_data); g_task_set_source_tag (task, secret_service_load_collections); closure = g_new0 (EnsureClosure, 1); closure->collections = collections_table_new (); g_task_set_task_data (task, closure, ensure_closure_free); g_variant_iter_init (&iter, paths); while (g_variant_iter_loop (&iter, "&o", &path)) { collection = service_lookup_collection (self, path); /* No such collection yet create a new one */ if (collection == NULL) { secret_collection_new_for_dbus_path (self, path, SECRET_COLLECTION_LOAD_ITEMS, cancellable, on_ensure_collection, g_object_ref (task)); closure->collections_loading++; } else { g_hash_table_insert (closure->collections, g_strdup (path), collection); } } if (closure->collections_loading == 0) { service_update_collections (self, closure->collections); g_task_return_boolean (task, TRUE); } g_variant_unref (paths); g_object_unref (task); } /** * secret_service_load_collections_finish: * @self: the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Complete an asynchronous operation to ensure that the #SecretService proxy * has loaded all the collections present in the Secret Service. * * Returns: whether the load was successful or not */ gboolean secret_service_load_collections_finish (SecretService *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_task_is_valid (result, self), FALSE); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == secret_service_load_collections, FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } /** * secret_service_load_collections_sync: * @self: the secret service * @cancellable: (nullable): optional cancellation object * @error: location to place an error on failure * * Ensure that the #SecretService proxy has loaded all the collections present * in the Secret Service. * * This affects the result of [method@Service.get_collections]. * * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to * [func@Service.get_sync] in order to ensure that the collections have been * loaded by the time you get the #SecretService proxy. * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the load was successful or not */ gboolean secret_service_load_collections_sync (SecretService *self, GCancellable *cancellable, GError **error) { SecretCollection *collection; GHashTable *collections; GVariant *paths; GVariantIter iter; const gchar *path; gboolean ret = TRUE; g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections"); g_return_val_if_fail (paths != NULL, FALSE); collections = collections_table_new (); g_variant_iter_init (&iter, paths); while (g_variant_iter_next (&iter, "&o", &path)) { collection = service_lookup_collection (self, path); /* No such collection yet create a new one */ if (collection == NULL) { collection = secret_collection_new_for_dbus_path_sync (self, path, SECRET_COLLECTION_LOAD_ITEMS, cancellable, error); if (collection == NULL) { ret = FALSE; break; } } g_hash_table_insert (collections, g_strdup (path), collection); } if (ret) service_update_collections (self, collections); g_hash_table_unref (collections); g_variant_unref (paths); return ret; } /** * secret_service_prompt_sync: * @self: the secret service * @prompt: the prompt * @cancellable: (nullable): optional cancellation object * @return_type: the variant type of the prompt result * @error: location to place an error on failure * * Perform prompting for a [class@Prompt]. * * Runs a prompt and performs the prompting. Returns a variant result if the * prompt was completed and not dismissed. The type of result depends on the * action the prompt is completing, and is defined in the Secret Service DBus * API specification. * * This function is called by other parts of this library to handle prompts * for the various actions that can require prompting. * * Override the #SecretServiceClass [vfunc@Service.prompt_sync] virtual method * to change the behavior of the prompting. The default behavior is to simply * run [method@Prompt.perform_sync] on the prompt with a %NULL `window_id`. * * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred, * a variant result if the prompt was successful */ GVariant * secret_service_prompt_sync (SecretService *self, SecretPrompt *prompt, GCancellable *cancellable, const GVariantType *return_type, GError **error) { SecretServiceClass *klass; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (SECRET_IS_PROMPT (prompt), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); klass = SECRET_SERVICE_GET_CLASS (self); g_return_val_if_fail (klass->prompt_sync != NULL, NULL); return (klass->prompt_sync) (self, prompt, cancellable, return_type, error); } /** * secret_service_prompt: * @self: the secret service * @prompt: the prompt * @return_type: (nullable): the variant type of the prompt result * @cancellable: (nullable): optional cancellation object * @callback: called when the operation completes * @user_data: data to be passed to the callback * * Perform prompting for a [class@Prompt]. * * This function is called by other parts of this library to handle prompts * for the various actions that can require prompting. * * Override the #SecretServiceClass [vfunc@Service.prompt_async] virtual method * to change the behavior of the prompting. The default behavior is to simply * run [method@Prompt.perform] on the prompt. */ void secret_service_prompt (SecretService *self, SecretPrompt *prompt, const GVariantType *return_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SecretServiceClass *klass; g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (SECRET_IS_PROMPT (prompt)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); klass = SECRET_SERVICE_GET_CLASS (self); g_return_if_fail (klass->prompt_async != NULL); (klass->prompt_async) (self, prompt, return_type, cancellable, callback, user_data); } /** * secret_service_prompt_finish: * @self: the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * * Complete asynchronous operation to perform prompting for a [class@Prompt]. * * Returns a variant result if the prompt was completed and not dismissed. The * type of result depends on the action the prompt is completing, and is defined * in the Secret Service DBus API specification. * * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred, * a variant result if the prompt was successful */ GVariant * secret_service_prompt_finish (SecretService *self, GAsyncResult *result, GError **error) { SecretServiceClass *klass; g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); klass = SECRET_SERVICE_GET_CLASS (self); g_return_val_if_fail (klass->prompt_finish != NULL, NULL); return (klass->prompt_finish) (self, result, error); } /** * secret_service_get_collection_gtype: * @self: the secret service * * Get the GObject type for collections instantiated by this service. * * This will always be either [class@Collection] or derived from it. * * Returns: the gobject type for collections */ GType secret_service_get_collection_gtype (SecretService *self) { SecretServiceClass *klass; GType type; g_return_val_if_fail (SECRET_IS_SERVICE (self), 0); klass = SECRET_SERVICE_GET_CLASS (self); g_return_val_if_fail (klass->get_collection_gtype != NULL, SECRET_TYPE_COLLECTION); type = (klass->get_collection_gtype) (self); g_return_val_if_fail (g_type_is_a (type, SECRET_TYPE_COLLECTION), SECRET_TYPE_COLLECTION); return type; } /** * secret_service_get_item_gtype: * @self: the service * * Get the GObject type for items instantiated by this service. * * This will always be either [class@Item] or derived from it. * * Returns: the gobject type for items */ GType secret_service_get_item_gtype (SecretService *self) { SecretServiceClass *klass; GType type; g_return_val_if_fail (SECRET_IS_SERVICE (self), 0); klass = SECRET_SERVICE_GET_CLASS (self); g_return_val_if_fail (klass->get_item_gtype != NULL, SECRET_TYPE_ITEM); type = (klass->get_item_gtype) (self); g_return_val_if_fail (g_type_is_a (type, SECRET_TYPE_ITEM), SECRET_TYPE_ITEM); return type; } 07070100000078000081A400000000000000000000000167D9F0D9000047D5000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/secret-service.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_SERVICE_H__ #define __SECRET_SERVICE_H__ #include #include "secret-prompt.h" #include "secret-schema.h" #include "secret-types.h" #include "secret-value.h" G_BEGIN_DECLS typedef enum { SECRET_SERVICE_NONE = 0, SECRET_SERVICE_OPEN_SESSION = 1 << 1, SECRET_SERVICE_LOAD_COLLECTIONS = 1 << 2, } SecretServiceFlags; #define SECRET_TYPE_SERVICE (secret_service_get_type ()) #define SECRET_SERVICE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), SECRET_TYPE_SERVICE, SecretService)) #define SECRET_SERVICE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), SECRET_TYPE_SERVICE, SecretServiceClass)) #define SECRET_IS_SERVICE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), SECRET_TYPE_SERVICE)) #define SECRET_IS_SERVICE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), SECRET_TYPE_SERVICE)) #define SECRET_SERVICE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), SECRET_TYPE_SERVICE, SecretServiceClass)) typedef struct _SecretCollection SecretCollection; typedef struct _SecretService SecretService; typedef struct _SecretServiceClass SecretServiceClass; typedef struct _SecretServicePrivate SecretServicePrivate; struct _SecretService { GDBusProxy parent; /*< private >*/ SecretServicePrivate *pv; }; struct _SecretServiceClass { GDBusProxyClass parent_class; GType collection_gtype; GType item_gtype; GVariant * (* prompt_sync) (SecretService *self, SecretPrompt *prompt, GCancellable *cancellable, const GVariantType *return_type, GError **error); void (* prompt_async) (SecretService *self, SecretPrompt *prompt, const GVariantType *return_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GVariant * (* prompt_finish) (SecretService *self, GAsyncResult *result, GError **error); GType (* get_collection_gtype) (SecretService *self); GType (* get_item_gtype) (SecretService *self); /*< private >*/ gpointer padding[14]; }; GType secret_service_get_type (void) G_GNUC_CONST; GType secret_service_get_collection_gtype (SecretService *self); GType secret_service_get_item_gtype (SecretService *self); void secret_service_get (SecretServiceFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretService * secret_service_get_finish (GAsyncResult *result, GError **error); SecretService * secret_service_get_sync (SecretServiceFlags flags, GCancellable *cancellable, GError **error); void secret_service_disconnect (void); void secret_service_open (GType service_gtype, const gchar *service_bus_name, SecretServiceFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretService * secret_service_open_finish (GAsyncResult *result, GError **error); SecretService * secret_service_open_sync (GType service_gtype, const gchar *service_bus_name, SecretServiceFlags flags, GCancellable *cancellable, GError **error); SecretServiceFlags secret_service_get_flags (SecretService *self); const gchar * secret_service_get_session_algorithms (SecretService *self); GList * secret_service_get_collections (SecretService *self); void secret_service_ensure_session (SecretService *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_service_ensure_session_finish (SecretService *self, GAsyncResult *result, GError **error); gboolean secret_service_ensure_session_sync (SecretService *self, GCancellable *cancellable, GError **error); void secret_service_load_collections (SecretService *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_service_load_collections_finish (SecretService *self, GAsyncResult *result, GError **error); gboolean secret_service_load_collections_sync (SecretService *self, GCancellable *cancellable, GError **error); GVariant * secret_service_prompt_sync (SecretService *self, SecretPrompt *prompt, GCancellable *cancellable, const GVariantType *return_type, GError **error); void secret_service_prompt (SecretService *self, SecretPrompt *prompt, const GVariantType *return_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GVariant * secret_service_prompt_finish (SecretService *self, GAsyncResult *result, GError **error); void secret_service_search (SecretService *service, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GList * secret_service_search_finish (SecretService *service, GAsyncResult *result, GError **error); GList * secret_service_search_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, GCancellable *cancellable, GError **error); void secret_service_lock (SecretService *service, GList *objects, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gint secret_service_lock_finish (SecretService *service, GAsyncResult *result, GList **locked, GError **error); gint secret_service_lock_sync (SecretService *service, GList *objects, GCancellable *cancellable, GList **locked, GError **error); void secret_service_unlock (SecretService *service, GList *objects, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gint secret_service_unlock_finish (SecretService *service, GAsyncResult *result, GList **unlocked, GError **error); gint secret_service_unlock_sync (SecretService *service, GList *objects, GCancellable *cancellable, GList **unlocked, GError **error); void secret_service_store (SecretService *service, const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_service_store_finish (SecretService *service, GAsyncResult *result, GError **error); gboolean secret_service_store_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, const gchar *collection, const gchar *label, SecretValue *value, GCancellable *cancellable, GError **error); void secret_service_lookup (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); SecretValue * secret_service_lookup_finish (SecretService *service, GAsyncResult *result, GError **error); SecretValue * secret_service_lookup_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); void secret_service_clear (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_service_clear_finish (SecretService *service, GAsyncResult *result, GError **error); gboolean secret_service_clear_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); void secret_service_set_alias (SecretService *service, const gchar *alias, SecretCollection *collection, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean secret_service_set_alias_finish (SecretService *service, GAsyncResult *result, GError **error); gboolean secret_service_set_alias_sync (SecretService *service, const gchar *alias, SecretCollection *collection, GCancellable *cancellable, GError **error); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecretService, g_object_unref) G_END_DECLS #endif /* __SECRET_SERVICE_H___ */ 07070100000079000081A400000000000000000000000167D9F0D90000543D000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/secret-session.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-private.h" #ifdef WITH_CRYPTO #include "egg/egg-dh.h" #include "egg/egg-fips.h" #include "egg/egg-hkdf.h" #endif #ifdef WITH_GCRYPT #include "egg/egg-libgcrypt.h" #include #endif #ifdef WITH_GNUTLS #include #endif #include "egg/egg-hex.h" #include "egg/egg-secure-memory.h" #include EGG_SECURE_DECLARE (secret_session); #define ALGORITHMS_AES "dh-ietf1024-sha256-aes128-cbc-pkcs7" #define ALGORITHMS_PLAIN "plain" struct _SecretSession { gchar *path; const gchar *algorithms; #ifdef WITH_CRYPTO egg_dh_params *params; egg_dh_privkey *privat; egg_dh_pubkey *publi; #endif gpointer key; gsize n_key; }; void _secret_session_free (gpointer data) { SecretSession *session = data; if (session == NULL) return; g_free (session->path); #ifdef WITH_CRYPTO egg_dh_pubkey_free (session->publi); egg_dh_privkey_free (session->privat); egg_dh_params_free (session->params); #endif egg_secure_free (session->key); g_free (session); } #ifdef WITH_CRYPTO static GVariant * request_open_session_aes (SecretSession *session) { GBytes *buffer; GVariant *argument; EggFipsMode fips_mode; g_assert (session->params == NULL); g_assert (session->privat == NULL); g_assert (session->publi == NULL); #ifdef WITH_GCRYPT egg_libgcrypt_initialize (); #endif /* Initialize our local parameters and values */ session->params = egg_dh_default_params ("ietf-ike-grp-modp-1024"); if (!session->params) g_return_val_if_reached (NULL); #if 0 g_printerr ("\n lib params: "); egg_dh_params_dump (session->params); g_printerr ("\n"); #endif fips_mode = egg_fips_get_mode (); egg_fips_set_mode (EGG_FIPS_MODE_DISABLED); if (!egg_dh_gen_pair (session->params, 0, &session->publi, &session->privat)) g_return_val_if_reached (NULL); egg_fips_set_mode (fips_mode); buffer = egg_dh_pubkey_export (session->publi); g_return_val_if_fail (buffer != NULL, NULL); argument = g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"), buffer, TRUE); g_bytes_unref (buffer); return g_variant_new ("(sv)", ALGORITHMS_AES, argument); } static gboolean response_open_session_aes (SecretSession *session, GVariant *response) { GBytes *buffer; GVariant *argument; const gchar *sig; egg_dh_pubkey *peer; GBytes *ikm; EggFipsMode fips_mode; sig = g_variant_get_type_string (response); g_return_val_if_fail (sig != NULL, FALSE); if (!g_str_equal (sig, "(vo)")) { g_warning ("invalid OpenSession() response from daemon with signature: %s", sig); return FALSE; } g_assert (session->path == NULL); g_variant_get (response, "(vo)", &argument, &session->path); buffer = g_variant_get_data_as_bytes (argument); peer = egg_dh_pubkey_new_from_bytes (session->params, buffer); g_bytes_unref (buffer); g_return_val_if_fail (peer != NULL, FALSE); g_variant_unref (argument); #if 0 g_printerr (" lib publi: "); egg_dh_pubkey_dump (session->publi); g_printerr ("\n lib peer: "); egg_dh_pubkey_dump (peer); g_printerr ("\n"); #endif fips_mode = egg_fips_get_mode (); egg_fips_set_mode (EGG_FIPS_MODE_DISABLED); ikm = egg_dh_gen_secret (peer, session->privat, session->params); egg_fips_set_mode (fips_mode); egg_dh_pubkey_free (peer); #if 0 g_printerr (" lib ikm: %s\n", egg_hex_encode (g_bytes_get_data (ikm, NULL), g_bytes_get_size (ikm))); #endif if (ikm == NULL) { g_warning ("couldn't negotiate a valid AES session key"); g_free (session->path); session->path = NULL; return FALSE; } session->n_key = 16; session->key = egg_secure_alloc (session->n_key); if (!egg_hkdf_perform ("sha256", g_bytes_get_data (ikm, NULL), g_bytes_get_size (ikm), NULL, 0, NULL, 0, session->key, session->n_key)) g_return_val_if_reached (FALSE); g_bytes_unref (ikm); session->algorithms = ALGORITHMS_AES; return TRUE; } #endif /* WITH_CRYPTO */ static GVariant * request_open_session_plain (SecretSession *session) { GVariant *argument = g_variant_new_string (""); return g_variant_new ("(sv)", "plain", argument); } static gboolean response_open_session_plain (SecretSession *session, GVariant *response) { GVariant *argument; const gchar *sig; sig = g_variant_get_type_string (response); g_return_val_if_fail (sig != NULL, FALSE); if (!g_str_equal (sig, "(vo)")) { g_warning ("invalid OpenSession() response from daemon with signature: %s", g_variant_get_type_string (response)); return FALSE; } g_assert (session->path == NULL); g_variant_get (response, "(vo)", &argument, &session->path); g_variant_unref (argument); g_assert (session->key == NULL); g_assert (session->n_key == 0); session->algorithms = ALGORITHMS_PLAIN; return TRUE; } typedef struct { SecretSession *session; } OpenSessionClosure; static void open_session_closure_free (gpointer data) { OpenSessionClosure *closure = data; g_assert (closure); _secret_session_free (closure->session); g_free (closure); } static void on_service_open_session_plain (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); OpenSessionClosure *closure = g_task_get_task_data (task); SecretService *service = SECRET_SERVICE (source); GError *error = NULL; GVariant *response; response = g_dbus_proxy_call_finish (G_DBUS_PROXY (service), result, &error); /* A successful response, decode it */ if (response != NULL) { if (response_open_session_plain (closure->session, response)) { _secret_service_take_session (service, closure->session); closure->session = NULL; g_task_return_boolean (task, TRUE); } else { g_task_return_new_error (task, SECRET_ERROR, SECRET_ERROR_PROTOCOL, _("Couldn’t communicate with the secret storage")); } g_variant_unref (response); } else { g_task_return_error (task, g_steal_pointer (&error)); } g_object_unref (task); } #ifdef WITH_CRYPTO static void on_service_open_session_aes (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); OpenSessionClosure * closure = g_task_get_task_data (task); SecretService *service = SECRET_SERVICE (source); GError *error = NULL; GVariant *response; response = g_dbus_proxy_call_finish (G_DBUS_PROXY (service), result, &error); /* A successful response, decode it */ if (response != NULL) { if (response_open_session_aes (closure->session, response)) { _secret_service_take_session (service, closure->session); closure->session = NULL; g_task_return_boolean (task, TRUE); } else { g_task_return_new_error (task, SECRET_ERROR, SECRET_ERROR_PROTOCOL, _("Couldn’t communicate with the secret storage")); } g_variant_unref (response); } else { /* AES session not supported, request a plain session */ if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED)) { g_dbus_proxy_call (G_DBUS_PROXY (source), "OpenSession", request_open_session_plain (closure->session), G_DBUS_CALL_FLAGS_NONE, -1, g_task_get_cancellable (task), on_service_open_session_plain, g_object_ref (task)); g_error_free (error); /* Other errors result in a failure */ } else { g_task_return_error (task, g_steal_pointer (&error)); } } g_object_unref (task); } #endif /* WITH_CRYPTO */ void _secret_session_open (SecretService *service, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; OpenSessionClosure *closure; task = g_task_new (service, cancellable, callback, user_data); g_task_set_source_tag (task, _secret_session_open); closure = g_new (OpenSessionClosure, 1); closure->session = g_new0 (SecretSession, 1); g_task_set_task_data (task, closure, open_session_closure_free); g_dbus_proxy_call (G_DBUS_PROXY (service), "OpenSession", #ifdef WITH_CRYPTO request_open_session_aes (closure->session), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_service_open_session_aes, #else request_open_session_plain (closure->session), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_service_open_session_plain, #endif g_object_ref (task)); g_object_unref (task); } gboolean _secret_session_open_finish (GAsyncResult *result, GError **error) { if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } #ifdef WITH_CRYPTO static gboolean pkcs7_unpad_bytes_in_place (guchar *padded, gsize *n_padded) { gsize n_pad, i; if (*n_padded == 0) return FALSE; n_pad = padded[*n_padded - 1]; /* Validate the padding */ if (n_pad == 0 || n_pad > 16) return FALSE; if (n_pad > *n_padded) return FALSE; for (i = *n_padded - n_pad; i < *n_padded; ++i) { if (padded[i] != n_pad) return FALSE; } /* The last bit of data */ *n_padded -= n_pad; /* Null teriminate as a courtesy */ padded[*n_padded] = 0; return TRUE; } #ifdef WITH_GCRYPT static SecretValue * service_decode_aes_secret (SecretSession *session, gconstpointer param, gsize n_param, gconstpointer value, gsize n_value, const gchar *content_type) { gcry_cipher_hd_t cih; gsize n_padded; gcry_error_t gcry; guchar *padded; gsize pos; if (n_param != 16) { g_info ("received an encrypted secret structure with invalid parameter"); return NULL; } if (n_value == 0 || n_value % 16 != 0) { g_info ("received an encrypted secret structure with bad secret length"); return NULL; } gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0); if (gcry != 0) { g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry)); return NULL; } #if 0 g_printerr (" lib iv: %s\n", egg_hex_encode (param, n_param)); #endif gcry = gcry_cipher_setiv (cih, param, n_param); g_return_val_if_fail (gcry == 0, NULL); #if 0 g_printerr (" lib key: %s\n", egg_hex_encode (session->key, session->n_key)); #endif gcry = gcry_cipher_setkey (cih, session->key, session->n_key); g_return_val_if_fail (gcry == 0, NULL); /* Copy the memory buffer */ n_padded = n_value; padded = egg_secure_alloc (n_padded); memcpy (padded, value, n_padded); /* Perform the decryption */ for (pos = 0; pos < n_padded; pos += 16) { gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, 16, NULL, 0); g_return_val_if_fail (gcry == 0, FALSE); } gcry_cipher_close (cih); /* Unpad the resulting value */ if (!pkcs7_unpad_bytes_in_place (padded, &n_padded)) { egg_secure_clear (padded, n_padded); egg_secure_free (padded); g_info ("received an invalid or unencryptable secret"); return FALSE; } return secret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free); } #endif /* WITH_GCRYPT */ #ifdef WITH_GNUTLS static SecretValue * service_decode_aes_secret (SecretSession *session, gconstpointer param, gsize n_param, gconstpointer value, gsize n_value, const gchar *content_type) { gnutls_cipher_hd_t cih; gnutls_datum_t iv, key; gsize n_padded; int ret; guchar *padded; if (n_param != 16) { g_info ("received an encrypted secret structure with invalid parameter"); return NULL; } if (n_value == 0 || n_value % 16 != 0) { g_info ("received an encrypted secret structure with bad secret length"); return NULL; } #if 0 g_printerr (" lib iv: %s\n", egg_hex_encode (param, n_param)); #endif #if 0 g_printerr (" lib key: %s\n", egg_hex_encode (session->key, session->n_key)); #endif iv.data = (void *)param; iv.size = n_param; key.data = session->key; key.size = session->n_key; ret = gnutls_cipher_init (&cih, GNUTLS_CIPHER_AES_128_CBC, &key, &iv); if (ret != 0) { g_warning ("couldn't create AES cipher: %s", gnutls_strerror (ret)); return NULL; } /* Copy the memory buffer */ n_padded = n_value; padded = egg_secure_alloc (n_padded); if (!padded) { gnutls_cipher_deinit (cih); return NULL; } memcpy (padded, value, n_padded); /* Perform the decryption */ ret = gnutls_cipher_decrypt2 (cih, padded, n_padded, padded, n_padded); if (ret < 0) { egg_secure_clear (padded, n_padded); egg_secure_free (padded); gnutls_cipher_deinit (cih); return NULL; } gnutls_cipher_deinit (cih); /* Unpad the resulting value */ if (!pkcs7_unpad_bytes_in_place (padded, &n_padded)) { egg_secure_clear (padded, n_padded); egg_secure_free (padded); g_info ("received an invalid or unencryptable secret"); return FALSE; } return secret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free); } #endif /* WITH_GNUTLS */ #endif /* WITH_CRYPTO */ static SecretValue * service_decode_plain_secret (SecretSession *session, gconstpointer param, gsize n_param, gconstpointer value, gsize n_value, const gchar *content_type) { if (n_param != 0) { g_info ("received a plain secret structure with invalid parameter"); return NULL; } return secret_value_new (value, n_value, content_type); } SecretValue * _secret_session_decode_secret (SecretSession *session, GVariant *encoded) { SecretValue *result; gconstpointer param; gconstpointer value; gchar *session_path; gchar *content_type; gsize n_param; gsize n_value; GVariant *vparam; GVariant *vvalue; g_return_val_if_fail (session != NULL, NULL); g_return_val_if_fail (encoded != NULL, NULL); /* Parsing (oayays) */ g_variant_get_child (encoded, 0, "o", &session_path); if (session_path == NULL || !g_str_equal (session_path, session->path)) { g_info ("received a secret encoded with wrong session: %s != %s", session_path, session->path); g_free (session_path); return NULL; } vparam = g_variant_get_child_value (encoded, 1); param = g_variant_get_fixed_array (vparam, &n_param, sizeof (guchar)); vvalue = g_variant_get_child_value (encoded, 2); value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar)); g_variant_get_child (encoded, 3, "s", &content_type); #ifdef WITH_CRYPTO if (session->key != NULL) result = service_decode_aes_secret (session, param, n_param, value, n_value, content_type); else #endif result = service_decode_plain_secret (session, param, n_param, value, n_value, content_type); g_variant_unref (vparam); g_variant_unref (vvalue); g_free (content_type); g_free (session_path); return result; } #ifdef WITH_CRYPTO static guchar* pkcs7_pad_bytes_in_secure_memory (gconstpointer secret, gsize length, gsize *n_padded) { gsize n_pad; guchar *padded; /* Pad the secret */ *n_padded = ((length + 16) / 16) * 16; g_assert (length < *n_padded); g_assert (*n_padded > 0); n_pad = *n_padded - length; g_assert (n_pad > 0 && n_pad <= 16); padded = egg_secure_alloc (*n_padded); memcpy (padded, secret, length); memset (padded + length, n_pad, n_pad); return padded; } #ifdef WITH_GCRYPT static gboolean service_encode_aes_secret (SecretSession *session, SecretValue *value, GVariantBuilder *builder) { gcry_cipher_hd_t cih; guchar *padded; gsize n_padded, pos; gcry_error_t gcry; gpointer iv; gconstpointer secret; gsize n_secret; GVariant *child; g_variant_builder_add (builder, "o", session->path); /* Create the cipher */ gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0); if (gcry != 0) { g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry)); return FALSE; } secret = secret_value_get (value, &n_secret); /* Perform the encoding here */ padded = pkcs7_pad_bytes_in_secure_memory (secret, n_secret, &n_padded); g_assert (padded != NULL); /* Setup the IV */ iv = g_malloc0 (16); gcry_create_nonce (iv, 16); gcry = gcry_cipher_setiv (cih, iv, 16); g_return_val_if_fail (gcry == 0, FALSE); /* Setup the key */ gcry = gcry_cipher_setkey (cih, session->key, session->n_key); g_return_val_if_fail (gcry == 0, FALSE); /* Perform the encryption */ for (pos = 0; pos < n_padded; pos += 16) { gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, 16, NULL, 0); g_return_val_if_fail (gcry == 0, FALSE); } gcry_cipher_close (cih); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv, 16, TRUE, g_free, iv); g_variant_builder_add_value (builder, child); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), padded, n_padded, TRUE, egg_secure_free, padded); g_variant_builder_add_value (builder, child); g_variant_builder_add (builder, "s", secret_value_get_content_type (value)); return TRUE; } #endif /* WITH_GCRYPT */ #ifdef WITH_GNUTLS static gboolean service_encode_aes_secret (SecretSession *session, SecretValue *value, GVariantBuilder *builder) { gnutls_cipher_hd_t cih = NULL; guchar *padded; gsize n_padded; int ret; gnutls_datum_t iv, key; gpointer iv_data; gconstpointer secret; gsize n_secret; GVariant *child; g_variant_builder_add (builder, "o", session->path); secret = secret_value_get (value, &n_secret); /* Perform the encoding here */ padded = pkcs7_pad_bytes_in_secure_memory (secret, n_secret, &n_padded); g_assert (padded != NULL); /* Setup the IV */ iv_data = g_malloc0 (16); iv.data = iv_data; iv.size = 16; ret = gnutls_rnd (GNUTLS_RND_NONCE, iv.data, iv.size); g_return_val_if_fail (ret >= 0, FALSE); /* Setup the key */ key.data = session->key; key.size = session->n_key; /* Create the cipher */ ret = gnutls_cipher_init (&cih, GNUTLS_CIPHER_AES_128_CBC, &key, &iv); if (ret < 0) { g_warning ("couldn't create AES cipher: %s", gnutls_strerror (ret)); return FALSE; } /* Perform the encryption */ ret = gnutls_cipher_encrypt2 (cih, padded, n_padded, padded, n_padded); if (ret < 0) { gnutls_cipher_deinit (cih); return FALSE; } gnutls_cipher_deinit (cih); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv_data, 16, TRUE, g_free, iv_data); g_variant_builder_add_value (builder, child); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), padded, n_padded, TRUE, egg_secure_free, padded); g_variant_builder_add_value (builder, child); g_variant_builder_add (builder, "s", secret_value_get_content_type (value)); return TRUE; } #endif /* WITH_GNUTLS */ #endif /* WITH_CRYPTO */ static gboolean service_encode_plain_secret (SecretSession *session, SecretValue *value, GVariantBuilder *builder) { gconstpointer secret; gsize n_secret; GVariant *child; g_variant_builder_add (builder, "o", session->path); secret = secret_value_get (value, &n_secret); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), "", 0, TRUE, NULL, NULL); g_variant_builder_add_value (builder, child); child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), secret, n_secret, TRUE, secret_value_unref, secret_value_ref (value)); g_variant_builder_add_value (builder, child); g_variant_builder_add (builder, "s", secret_value_get_content_type (value)); return TRUE; } GVariant * _secret_session_encode_secret (SecretSession *session, SecretValue *value) { GVariantBuilder *builder; GVariant *result = NULL; GVariantType *type; gboolean ret; g_return_val_if_fail (session != NULL, NULL); g_return_val_if_fail (value != NULL, NULL); type = g_variant_type_new ("(oayays)"); builder = g_variant_builder_new (type); #ifdef WITH_CRYPTO if (session->key) ret = service_encode_aes_secret (session, value, builder); else #endif ret = service_encode_plain_secret (session, value, builder); if (ret) result = g_variant_builder_end (builder); g_variant_builder_unref (builder); g_variant_type_free (type); return result; } const gchar * _secret_session_get_algorithms (SecretSession *session) { g_return_val_if_fail (session != NULL, NULL); return session->algorithms; } const gchar * _secret_session_get_path (SecretSession *session) { g_return_val_if_fail (session != NULL, NULL); return session->path; } 0707010000007A000081A400000000000000000000000167D9F0D9000005AB000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/secret-types.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_TYPES_H__ #define __SECRET_TYPES_H__ #include G_BEGIN_DECLS #define SECRET_ERROR (secret_error_get_quark ()) GQuark secret_error_get_quark (void) G_GNUC_CONST; typedef enum { SECRET_ERROR_PROTOCOL = 1, SECRET_ERROR_IS_LOCKED = 2, SECRET_ERROR_NO_SUCH_OBJECT = 3, SECRET_ERROR_ALREADY_EXISTS = 4, SECRET_ERROR_INVALID_FILE_FORMAT = 5, SECRET_ERROR_MISMATCHED_SCHEMA = 6, SECRET_ERROR_NO_MATCHING_ATTRIBUTE = 7, SECRET_ERROR_WRONG_TYPE = 8, SECRET_ERROR_EMPTY_TABLE = 9, } SecretError; #define SECRET_COLLECTION_DEFAULT "default" #define SECRET_COLLECTION_SESSION "session" typedef enum { SECRET_SEARCH_NONE = 0, SECRET_SEARCH_ALL = 1 << 1, SECRET_SEARCH_UNLOCK = 1 << 2, SECRET_SEARCH_LOAD_SECRETS = 1 << 3, } SecretSearchFlags; G_END_DECLS #endif /* __G_SERVICE_H___ */ 0707010000007B000081A400000000000000000000000167D9F0D900003407000000000000000000000000000000000000002900000000libsecret-0.21.7/libsecret/secret-util.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-private.h" #include "secret-types.h" #include /** * SecretError: * @SECRET_ERROR_PROTOCOL: received an invalid data or message from the Secret * Service * @SECRET_ERROR_IS_LOCKED: the item or collection is locked and the operation * cannot be performed * @SECRET_ERROR_NO_SUCH_OBJECT: no such item or collection found in the Secret * Service * @SECRET_ERROR_ALREADY_EXISTS: a relevant item or collection already exists * @SECRET_ERROR_INVALID_FILE_FORMAT: the file format is not valid * * Errors returned by the Secret Service. * * None of the errors are appropriate for display to the user. It is up to the * application to handle them appropriately. * * Stability: Stable */ /** * SECRET_ERROR_MISMATCHED_SCHEMA: * * the xdg:schema attribute of the table does not match the schema name * * Since: 0.21.2 */ /** * SECRET_ERROR_NO_MATCHING_ATTRIBUTE: * * attribute contained in table not found in corresponding schema * * Since: 0.21.2 */ /** * SECRET_ERROR_WRONG_TYPE: * * attribute could not be parsed according to its type reported in the table's * schema * * Since: 0.21.2 */ /** * SECRET_ERROR_EMPTY_TABLE: * * attribute list passed to secret_attributes_validate has no elements to * validate * * Since: 0.21.2 */ static void list_unref_free (GList *reflist) { GList *l; for (l = reflist; l; l = g_list_next (l)) { g_return_if_fail (G_IS_OBJECT (l->data)); g_object_unref (l->data); } g_list_free (reflist); } static GList * list_ref_copy (GList *reflist) { GList *l, *copy = g_list_copy (reflist); for (l = copy; l; l = g_list_next (l)) { g_return_val_if_fail (G_IS_OBJECT (l->data), NULL); g_object_ref (l->data); } return copy; } GType _secret_list_get_type (void) { static GType type = 0; if (!type) type = g_boxed_type_register_static ("SecretObjectList", (GBoxedCopyFunc)list_ref_copy, (GBoxedFreeFunc)list_unref_free); return type; } /** * secret_error_get_quark: * * Get the error quark. * * Returns: the quark */ GQuark secret_error_get_quark (void) { static gsize quark = 0; static const GDBusErrorEntry entries[] = { { SECRET_ERROR_IS_LOCKED, "org.freedesktop.Secret.Error.IsLocked", }, { SECRET_ERROR_NO_SUCH_OBJECT, "org.freedesktop.Secret.Error.NoSuchObject", }, { SECRET_ERROR_ALREADY_EXISTS, "org.freedesktop.Secret.Error.AlreadyExists" }, }; g_dbus_error_register_error_domain ("secret-error", &quark, entries, G_N_ELEMENTS (entries)); return quark; } void _secret_util_strip_remote_error (GError **error) { gchar *remote; if (error == NULL || *error == NULL) return; remote = g_dbus_error_get_remote_error (*error); if (remote) { if (g_dbus_error_strip_remote_error (*error)) { g_info ("Remote error from secret service: %s: %s", remote, (*error)->message); } g_free (remote); } } gchar * _secret_util_parent_path (const gchar *path) { const gchar *pos; g_return_val_if_fail (path != NULL, NULL); pos = strrchr (path, '/'); g_return_val_if_fail (pos != NULL, NULL); g_return_val_if_fail (pos != path, NULL); return g_strndup (path, pos - path); } gboolean _secret_util_empty_path (const gchar *path) { g_return_val_if_fail (path != NULL, TRUE); return (g_str_equal (path, "") || g_str_equal (path, "/")); } gchar * _secret_util_collection_to_path (const gchar *collection) { if (collection == NULL) collection = SECRET_COLLECTION_DEFAULT; if (strchr (collection, '/') == NULL) return g_strdup_printf ("/org/freedesktop/secrets/aliases/%s", collection); return g_strdup (collection); } GVariant * _secret_util_variant_for_properties (GHashTable *properties) { GHashTableIter iter; GVariantBuilder builder; const gchar *name; GVariant *value; g_return_val_if_fail (properties != NULL, NULL); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); g_hash_table_iter_init (&iter, properties); while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&value)) g_variant_builder_add (&builder, "{sv}", name, value); return g_variant_builder_end (&builder); } static void process_get_all_reply (GDBusProxy *proxy, GVariant *retval) { const gchar *invalidated_properties[1] = { NULL }; GVariant *changed_properties; GVariantIter *iter; GVariant *value; gchar *key; if (!g_variant_is_of_type (retval, G_VARIANT_TYPE ("(a{sv})"))) { g_warning ("Value for GetAll reply with type `%s' does not match `(a{sv})'", g_variant_get_type_string (retval)); return; } g_variant_get (retval, "(a{sv})", &iter); while (g_variant_iter_loop (iter, "{sv}", &key, &value)) g_dbus_proxy_set_cached_property (proxy, key, value); g_variant_iter_free (iter); g_variant_get (retval, "(@a{sv})", &changed_properties); g_signal_emit_by_name (proxy, "g-properties-changed", changed_properties, invalidated_properties); g_variant_unref (changed_properties); } static void on_get_properties (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); GDBusProxy *proxy = G_DBUS_PROXY (g_task_get_source_object (task)); GError *error = NULL; GVariant *retval; retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); if (error == NULL) { process_get_all_reply (proxy, retval); g_task_return_boolean (task, TRUE); } else { g_task_return_error (task, g_steal_pointer (&error)); } if (retval != NULL) g_variant_unref (retval); g_clear_object (&task); } void _secret_util_get_properties (GDBusProxy *proxy, gpointer result_tag, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (proxy, cancellable, callback, user_data); g_task_set_source_tag (task, result_tag); g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), g_dbus_proxy_get_name (proxy), g_dbus_proxy_get_object_path (proxy), "org.freedesktop.DBus.Properties", "GetAll", g_variant_new ("(s)", g_dbus_proxy_get_interface_name (proxy)), G_VARIANT_TYPE ("(a{sv})"), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_get_properties, g_steal_pointer (&task)); g_clear_object (&task); } gboolean _secret_util_get_properties_finish (GDBusProxy *proxy, gpointer result_tag, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, proxy), FALSE); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == result_tag, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } typedef struct { gchar *property; GVariant *value; gboolean result; } SetClosure; static void set_closure_free (gpointer data) { SetClosure *closure = data; g_free (closure->property); g_variant_unref (closure->value); g_free (closure); } static void on_set_property (GObject *source, GAsyncResult *result, gpointer user_data) { GTask *task = G_TASK (user_data); SetClosure *closure = g_task_get_task_data (task); GDBusProxy *proxy = G_DBUS_PROXY (g_task_get_source_object (user_data)); GError *error = NULL; GVariant *retval; gboolean success = FALSE; retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); } else { success = (retval != NULL); if (success) { g_dbus_proxy_set_cached_property (proxy, closure->property, closure->value); g_variant_unref (retval); } g_task_return_boolean (task, success); } g_clear_object (&task); } void _secret_util_set_property (GDBusProxy *proxy, const gchar *property, GVariant *value, gpointer result_tag, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; SetClosure *closure; g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (proxy, cancellable, callback, user_data); g_task_set_source_tag (task, result_tag); closure = g_new0 (SetClosure, 1); closure->property = g_strdup (property); closure->value = g_variant_ref_sink (value); g_task_set_task_data (task, closure, set_closure_free); g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), g_dbus_proxy_get_name (proxy), g_dbus_proxy_get_object_path (proxy), SECRET_PROPERTIES_INTERFACE, "Set", g_variant_new ("(ssv)", g_dbus_proxy_get_interface_name (proxy), property, closure->value), G_VARIANT_TYPE ("()"), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, cancellable, on_set_property, g_steal_pointer (&task)); g_clear_object (&task); } gboolean _secret_util_set_property_finish (GDBusProxy *proxy, gpointer result_tag, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, proxy), FALSE); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == result_tag, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (!g_task_propagate_boolean (G_TASK (result), error)) { _secret_util_strip_remote_error (error); return FALSE; } return TRUE; } gboolean _secret_util_set_property_sync (GDBusProxy *proxy, const gchar *property, GVariant *value, GCancellable *cancellable, GError **error) { gboolean result = FALSE; GVariant *retval; g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_variant_ref_sink (value); retval = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (proxy), g_dbus_proxy_get_name (proxy), g_dbus_proxy_get_object_path (proxy), SECRET_PROPERTIES_INTERFACE, "Set", g_variant_new ("(ssv)", g_dbus_proxy_get_interface_name (proxy), property, value), G_VARIANT_TYPE ("()"), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, cancellable, error); if (retval != NULL) { result = TRUE; g_variant_unref (retval); g_dbus_proxy_set_cached_property (proxy, property, value); } g_variant_unref (value); return result; } gboolean _secret_util_have_cached_properties (GDBusProxy *proxy) { gchar **names; names = g_dbus_proxy_get_cached_property_names (proxy); g_strfreev (names); return names != NULL; } SecretSync * _secret_sync_new (void) { SecretSync *sync; sync = g_new0 (SecretSync, 1); sync->context = g_main_context_new (); sync->loop = g_main_loop_new (sync->context, FALSE); return sync; } void _secret_sync_free (gpointer data) { SecretSync *sync = data; while (g_main_context_iteration (sync->context, FALSE)); g_clear_object (&sync->result); g_main_loop_unref (sync->loop); g_main_context_unref (sync->context); g_free (sync); } void _secret_sync_on_result (GObject *source, GAsyncResult *result, gpointer user_data) { SecretSync *sync = user_data; g_assert (sync->result == NULL); sync->result = g_object_ref (result); g_main_loop_quit (sync->loop); } 0707010000007C000081A400000000000000000000000167D9F0D900001FAB000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/secret-value.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "secret-private.h" #include "secret-value.h" #include "egg/egg-secure-memory.h" #include /** * SecretValue: * * A value containing a secret * * A #SecretValue contains a password or other secret value. * * Use [method@Value.get] to get the actual secret data, such as a password. * The secret data is not necessarily null-terminated, unless the content type * is "text/plain". * * Each #SecretValue has a content type. For passwords, this is `text/plain`. * Use [method@Value.get_content_type] to look at the content type. * * #SecretValue is reference counted and immutable. The secret data is only * freed when all references have been released via [method@Value.unref]. * * Stability: Stable */ static gboolean is_password_value (SecretValue *value); EGG_SECURE_DECLARE (secret_value); struct _SecretValue { gint refs; gpointer secret; gsize length; GDestroyNotify destroy; gchar *content_type; }; GType secret_value_get_type (void) { static gsize initialized = 0; static GType type = 0; if (g_once_init_enter (&initialized)) { type = g_boxed_type_register_static ("SecretValue", (GBoxedCopyFunc)secret_value_ref, (GBoxedFreeFunc)secret_value_unref); g_once_init_leave (&initialized, 1); } return type; } /** * secret_value_new: * @secret: the secret data * @length: the length of the data * @content_type: the content type of the data * * Create a #SecretValue for the secret data passed in. * * The secret data is copied into non-pageable 'secure' memory. * * If the length is less than zero, then @secret is assumed to be * null-terminated. * * Returns: (transfer full): the new #SecretValue */ SecretValue * secret_value_new (const gchar *secret, gssize length, const gchar *content_type) { gchar *copy; g_return_val_if_fail (length == 0 || secret != NULL, NULL); g_return_val_if_fail (content_type, NULL); if (length < 0) length = strlen (secret); copy = egg_secure_alloc (length + 1); if (secret) memcpy (copy, secret, length); copy[length] = 0; return secret_value_new_full (copy, length, content_type, egg_secure_free); } /** * secret_value_new_full: * @secret: the secret data * @length: the length of the data * @content_type: the content type of the data * @destroy: function to call to free the secret data * * Create a #SecretValue for the secret data passed in. * * The secret data is not copied, and will later be freed with the @destroy * function. * * If the length is less than zero, then @secret is assumed to be * null-terminated. * * Returns: (transfer full): the new #SecretValue */ SecretValue * secret_value_new_full (gchar *secret, gssize length, const gchar *content_type, GDestroyNotify destroy) { SecretValue *value; g_return_val_if_fail (content_type, NULL); if (length < 0) length = strlen (secret); value = g_new0 (SecretValue, 1); value->refs = 1; value->content_type = g_strdup (content_type); value->destroy = destroy; value->length = length; value->secret = secret; return value; } /** * secret_value_get: * @value: the value * @length: the length of the secret * * Get the secret data in the #SecretValue. * * The value is not necessarily null-terminated unless it was created with * [ctor@Value.new] or a null-terminated string was passed to * [ctor@Value.new_full]. * * Returns: (array length=length) (element-type guint8): the secret data */ const gchar * secret_value_get (SecretValue *value, gsize *length) { g_return_val_if_fail (value, NULL); if (length) *length = value->length; return value->secret; } /** * secret_value_get_text: * @value: the value * * Get the secret data in the #SecretValue if it contains a textual * value. * * The content type must be `text/plain`. * * Returns: (nullable): the value */ const gchar * secret_value_get_text (SecretValue *value) { g_return_val_if_fail (value, NULL); if (!is_password_value (value)) return NULL; return value->secret; } /** * secret_value_get_content_type: * @value: the value * * Get the content type of the secret value, such as * `text/plain`. * * Returns: the content type */ const gchar * secret_value_get_content_type (SecretValue *value) { g_return_val_if_fail (value, NULL); return value->content_type; } /** * secret_value_ref: * @value: value to reference * * Add another reference to the #SecretValue. * * For each reference [method@Value.unref] should be called to unreference the * value. * * Returns: (transfer full): the value */ SecretValue * secret_value_ref (SecretValue *value) { g_return_val_if_fail (value, NULL); g_atomic_int_inc (&value->refs); return value; } /** * secret_value_unref: * @value: (type Secret.Value): value to unreference * * Unreference a #SecretValue. * * When the last reference is gone, then the value will be freed. */ void secret_value_unref (gpointer value) { SecretValue *val = value; g_return_if_fail (value != NULL); if (g_atomic_int_dec_and_test (&val->refs)) { g_free (val->content_type); if (val->destroy) (val->destroy) (val->secret); g_free (val); } } static gboolean is_password_value (SecretValue *value) { if (value->content_type && g_str_equal (value->content_type, "text/plain")) return TRUE; /* gnome-keyring-daemon used to return passwords like this, so support this, but validate */ if (!value->content_type || g_str_equal (value->content_type, "application/octet-stream")) return g_utf8_validate (value->secret, value->length, NULL); return FALSE; } /** * secret_value_unref_to_password: * @value: the value * @length: (inout): the length of the secret * * Unreference a #SecretValue and steal the secret data in * #SecretValue as nonpageable memory. * * Returns: (transfer full): a new password string stored in nonpageable memory * which must be freed with [func@password_free] when done * * Since: 0.19.0 */ gchar * secret_value_unref_to_password (SecretValue *value, gsize *length) { SecretValue *val = value; gchar *result; g_return_val_if_fail (value != NULL, NULL); if (g_atomic_int_dec_and_test (&val->refs)) { if (val->destroy == egg_secure_free) { result = val->secret; if (length) *length = val->length; } else { result = egg_secure_strndup (val->secret, val->length); if (val->destroy) (val->destroy) (val->secret); if (length) *length = val->length; } g_free (val->content_type); g_free (val); } else { result = egg_secure_strndup (val->secret, val->length); if (length) *length = val->length; } return result; } gchar * _secret_value_unref_to_password (SecretValue *value) { g_return_val_if_fail (value != NULL, NULL); if (!is_password_value (value)) { secret_value_unref (value); return NULL; } return secret_value_unref_to_password (value, NULL); } gchar * _secret_value_unref_to_string (SecretValue *value) { SecretValue *val = value; gchar *result; g_return_val_if_fail (value != NULL, NULL); if (!is_password_value (value)) { secret_value_unref (value); return NULL; } if (g_atomic_int_dec_and_test (&val->refs)) { if (val->destroy == g_free) { result = val->secret; } else { result = g_strndup (val->secret, val->length); if (val->destroy) (val->destroy) (val->secret); } g_free (val->content_type); g_free (val); } else { result = g_strndup (val->secret, val->length); } return result; } 0707010000007D000081A400000000000000000000000167D9F0D900000810000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/secret-value.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_VALUE_H__ #define __SECRET_VALUE_H__ #include #include "secret-types.h" G_BEGIN_DECLS typedef struct _SecretValue SecretValue; #define SECRET_TYPE_VALUE (secret_value_get_type ()) GType secret_value_get_type (void) G_GNUC_CONST; SecretValue * secret_value_new (const gchar *secret, gssize length, const gchar *content_type); SecretValue * secret_value_new_full (gchar *secret, gssize length, const gchar *content_type, GDestroyNotify destroy); const gchar * secret_value_get (SecretValue *value, gsize *length); const gchar * secret_value_get_text (SecretValue *value); const gchar * secret_value_get_content_type (SecretValue *value); SecretValue * secret_value_ref (SecretValue *value); void secret_value_unref (gpointer value); gchar * secret_value_unref_to_password (SecretValue *value, gsize *length); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecretValue, secret_value_unref) G_END_DECLS #endif /* __SECRET_VALUE_H___ */ 0707010000007E000081A400000000000000000000000167D9F0D9000006BA000000000000000000000000000000000000002F00000000libsecret-0.21.7/libsecret/secret-version.h.in/* libsecret - GLib wrapper for Secret Service * * Copyright 2019 Sutou Kouhei * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Sutou Kouhei */ #if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) #error "Only can be included directly." #endif #ifndef __SECRET_VERSION_H__ #define __SECRET_VERSION_H__ /** * SECRET_MAJOR_VERSION: * * The major version of libsecret. */ #define SECRET_MAJOR_VERSION (@SECRET_MAJOR_VERSION@) /** * SECRET_MINOR_VERSION: * * The minor version of libsecret. */ #define SECRET_MINOR_VERSION (@SECRET_MINOR_VERSION@) /** * SECRET_MICRO_VERSION: * * The micro version of libsecret. */ #define SECRET_MICRO_VERSION (@SECRET_MICRO_VERSION@) /** * SECRET_CHECK_VERSION: * @major: major version to be satisfied * @minor: minor version to be satisfied * @micro: micro version to be satisfied * * Returns `TRUE` if using libsecret is newer than or equal to the * given version. */ #define SECRET_CHECK_VERSION(major, minor, micro) \ (SECRET_MAJOR_VERSION > (major) || \ (SECRET_MAJOR_VERSION == (major) && \ SECRET_MINOR_VERSION > (minor)) || \ (SECRET_MAJOR_VERSION == (major) && \ SECRET_MINOR_VERSION == (minor) && \ SECRET_MICRO_VERSION >= (micro))) #endif /* __SECRET_VERSION_H__ */ 0707010000007F000081A400000000000000000000000167D9F0D9000005EF000000000000000000000000000000000000002400000000libsecret-0.21.7/libsecret/secret.h/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #ifndef __SECRET_H__ #define __SECRET_H__ #include #define __SECRET_INSIDE_HEADER__ #include #include #include #include #include #include #include #include #include #include #include #include #include /* SECRET_WITH_UNSTABLE is defined in the secret-unstable.pc pkg-config file */ #if defined(SECRET_WITH_UNSTABLE) || defined(SECRET_API_SUBJECT_TO_CHANGE) #ifndef SECRET_API_SUBJECT_TO_CHANGE #warning "Some parts of the libsecret API are unstable. Define SECRET_API_SUBJECT_TO_CHANGE to acknowledge" #endif #include #endif /* SECRET_WITH_UNSTABLE || SECRET_API_SUBJECT_TO_CHANGE */ #undef __SECRET_INSIDE_HEADER__ #endif /* __SECRET_H__ */ 07070100000080000081A400000000000000000000000167D9F0D90000226D000000000000000000000000000000000000002D00000000libsecret-0.21.7/libsecret/test-attributes.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-attributes.h" #include "secret-private.h" #include "egg/egg-testing.h" #include #include #include static const SecretSchema MOCK_SCHEMA = { "org.mock.Schema", SECRET_SCHEMA_DONT_MATCH_NAME, { { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, { "bad-type", -1 }, } }; static void test_build (void) { GHashTable *attributes; attributes = secret_attributes_build (&MOCK_SCHEMA, "number", 4, "string", "four", "even", TRUE, NULL); g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "4"); g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "four"); g_assert_cmpstr (g_hash_table_lookup (attributes, "even"), ==, "true"); g_hash_table_unref (attributes); } static void test_build_unknown (void) { GHashTable *attributes; if (g_test_subprocess ()) { attributes = secret_attributes_build (&MOCK_SCHEMA, "invalid", "whee", "string", "four", "even", TRUE, NULL); g_assert_null (attributes); return; } g_test_trap_subprocess ("/attributes/build-unknown", 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*was not found in*"); } static void test_build_null_string (void) { GHashTable *attributes; if (g_test_subprocess ()) { attributes = secret_attributes_build (&MOCK_SCHEMA, "number", 4, "string", NULL, "even", TRUE, NULL); g_assert_null (attributes); return; } g_test_trap_subprocess ("/attributes/build-null-string", 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*attribute*NULL*"); } static void test_build_non_utf8_string (void) { GHashTable *attributes; if (g_test_subprocess ()) { attributes = secret_attributes_build (&MOCK_SCHEMA, "number", 4, "string", "\xfftest", "even", TRUE, NULL); g_assert_null (attributes); return; } g_test_trap_subprocess ("/attributes/build-non-utf8-string", 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*attribute*UTF-8*"); } static void test_build_bad_type (void) { GHashTable *attributes; if (g_test_subprocess ()) { attributes = secret_attributes_build (&MOCK_SCHEMA, "bad-type", "test", NULL); g_assert_null (attributes); return; } g_test_trap_subprocess ("/attributes/build-bad-type", 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*invalid type*"); } static void test_validate_schema (void) { GHashTable *attributes; gboolean ret; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_replace (attributes, "number", "1"); g_hash_table_replace (attributes, "string", "test"); g_hash_table_replace (attributes, "xdg:schema", "org.mock.Schema"); ret = _secret_attributes_validate (&MOCK_SCHEMA, attributes, G_STRFUNC, TRUE); g_assert_true (ret); g_hash_table_unref (attributes); } static void test_validate_schema_empty_ok (void) { GHashTable *attributes; gboolean ret; attributes = g_hash_table_new (g_str_hash, g_str_equal); ret = _secret_attributes_validate (&MOCK_SCHEMA, attributes, G_STRFUNC, FALSE); g_assert_true (ret); g_hash_table_unref (attributes); } static void test_validate_schema_bad_empty_not_ok (void) { GHashTable *attributes; gboolean ret; if (g_test_subprocess ()) { attributes = g_hash_table_new (g_str_hash, g_str_equal); ret = _secret_attributes_validate (&MOCK_SCHEMA, attributes, G_STRFUNC, TRUE); g_assert_false (ret); g_hash_table_unref (attributes); return; } g_test_trap_subprocess ("/attributes/validate-schema-bad-empty-not-ok", 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); g_test_trap_assert_failed (); } static void test_validate_schema_bad_mismatched_schema (void) { GHashTable *attributes; gboolean ret; if (g_test_subprocess ()) { attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_replace (attributes, "number", "1"); g_hash_table_replace (attributes, "string", "test"); g_hash_table_replace (attributes, "xdg:schema", "mismatched.Schema"); ret = _secret_attributes_validate (&MOCK_SCHEMA, attributes, G_STRFUNC, TRUE); g_assert_false (ret); g_hash_table_unref (attributes); return; } g_test_trap_subprocess ("/attributes/validate-schema-bad-mismatched-schema", 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); g_test_trap_assert_failed (); } static void test_validate_schema_bad_wrong_type (void) { GHashTable *attributes; gboolean ret; char non_utf8_string[] = {(char) 128, '\0'}; if (g_test_subprocess ()) { attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_replace (attributes, "number", "string_in_wrong_place"); g_hash_table_replace (attributes, "string", non_utf8_string); g_hash_table_replace (attributes, "even", "neither_true_nor_false"); g_hash_table_replace (attributes, "xdg:schema", "org.mock.Schema"); ret = _secret_attributes_validate (&MOCK_SCHEMA, attributes, G_STRFUNC, TRUE); g_assert_false (ret); g_hash_table_unref (attributes); return; } g_test_trap_subprocess ("/attributes/validate-schema-bad-wrong-type", 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); g_test_trap_assert_failed (); } static void test_validate_schema_bad_fake_key (void) { GHashTable *attributes; gboolean ret; if (g_test_subprocess ()) { attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_replace (attributes, "number", "1"); g_hash_table_replace (attributes, "string", "test"); g_hash_table_replace (attributes, "xdg:schema", "org.mock.Schema"); g_hash_table_replace (attributes, "made_up_key", "not_valid"); ret = _secret_attributes_validate (&MOCK_SCHEMA, attributes, G_STRFUNC, TRUE); g_assert_false (ret); g_hash_table_unref (attributes); return; } g_test_trap_subprocess ("/attributes/validate-schema-bad-fake-key", 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); g_test_trap_assert_failed (); } static void test_validate_libgnomekeyring (void) { GHashTable *attributes; gboolean ret; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_replace (attributes, "number", "1"); g_hash_table_replace (attributes, "string", "test"); g_hash_table_replace (attributes, "gkr:compat", "blah-dee-blah"); ret = _secret_attributes_validate (&MOCK_SCHEMA, attributes, G_STRFUNC, TRUE); g_assert_true (ret); g_hash_table_unref (attributes); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-attributes"); g_test_add_func ("/attributes/build", test_build); g_test_add_func ("/attributes/build-unknown", test_build_unknown); g_test_add_func ("/attributes/build-null-string", test_build_null_string); g_test_add_func ("/attributes/build-non-utf8-string", test_build_non_utf8_string); g_test_add_func ("/attributes/build-bad-type", test_build_bad_type); g_test_add_func ("/attributes/validate-schema", test_validate_schema); g_test_add_func ("/attributes/validate-schema-empty-ok", test_validate_schema_empty_ok); g_test_add_func ("/attributes/validate-schema-bad-empty-not-ok", test_validate_schema_bad_empty_not_ok); g_test_add_func ("/attributes/validate-schema-bad-mismatched-schema", test_validate_schema_bad_mismatched_schema); g_test_add_func ("/attributes/validate-schema-bad-wrong-type", test_validate_schema_bad_wrong_type); g_test_add_func ("/attributes/validate-schema-bad-fake-key", test_validate_schema_bad_fake_key); g_test_add_func ("/attributes/validate-libgnomekeyring", test_validate_libgnomekeyring); return g_test_run (); } 07070100000081000081A400000000000000000000000167D9F0D90000896F000000000000000000000000000000000000002D00000000libsecret-0.21.7/libsecret/test-collection.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-collection.h" #include "secret-service.h" #include "secret-paths.h" #include "secret-private.h" #include "mock-service.h" #include "egg/egg-testing.h" #include #include #include typedef struct { SecretService *service; } Test; static const SecretSchema MOCK_SCHEMA = { "org.mock.Schema", SECRET_SCHEMA_NONE, { { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, } }; static void setup (Test *test, gconstpointer data) { GError *error = NULL; const gchar *mock_script = data; mock_service_start (mock_script, &error); g_assert_no_error (error); test->service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (test->service), (gpointer *)&test->service); } static void teardown (Test *test, gconstpointer unused) { g_object_unref (test->service); secret_service_disconnect (); g_assert_null (test->service); mock_service_stop (); } static void on_async_result (GObject *source, GAsyncResult *result, gpointer user_data) { GAsyncResult **ret = user_data; g_assert_nonnull (ret); g_assert_null (*ret); *ret = g_object_ref (result); egg_test_wait_stop (); } static void on_notify_stop (GObject *obj, GParamSpec *spec, gpointer user_data) { guint *sigs = user_data; g_assert_nonnull (sigs); g_assert_true (*sigs > 0); if (--(*sigs) == 0) egg_test_wait_stop (); } static void test_new_sync (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GError *error = NULL; SecretCollection *collection; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (collection), (gpointer *)&collection); g_assert_cmpstr (g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)), ==, collection_path); g_object_unref (collection); g_assert_null (collection); } static void test_new_async (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GError *error = NULL; SecretCollection *collection; GAsyncResult *result = NULL; secret_collection_new_for_dbus_path (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); collection = secret_collection_new_for_dbus_path_finish (result, &error); g_assert_no_error (error); g_object_unref (result); g_object_add_weak_pointer (G_OBJECT (collection), (gpointer *)&collection); g_assert_cmpstr (g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)), ==, collection_path); g_object_unref (collection); g_assert_null (collection); } static void test_new_sync_noexist (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/nonexistant"; GError *error = NULL; SecretCollection *collection; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); g_assert_null (collection); g_clear_error (&error); } static void test_new_async_noexist (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/nonexistant"; GError *error = NULL; SecretCollection *collection; GAsyncResult *result = NULL; secret_collection_new_for_dbus_path (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); collection = secret_collection_new_for_dbus_path_finish (result, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); g_assert_null (collection); g_clear_error (&error); g_object_unref (result); } static void test_for_alias_sync (Test *test, gconstpointer used) { const gchar *collection_path; SecretCollection *collection; GError *error = NULL; collection = secret_collection_for_alias_sync (test->service, "default", SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)); g_assert_cmpstr (collection_path, ==, "/org/freedesktop/secrets/collection/english"); g_assert_cmpuint (secret_collection_get_flags (collection), ==, SECRET_COLLECTION_NONE); g_assert_null (secret_collection_get_items (collection)); g_object_unref (collection); collection = secret_collection_for_alias_sync (test->service, "unknown", SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); g_assert_null (collection); } static void test_for_alias_async (Test *test, gconstpointer used) { const gchar *collection_path; SecretCollection *collection; GAsyncResult *result = NULL; GError *error = NULL; secret_collection_for_alias (test->service, "default", SECRET_COLLECTION_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); collection = secret_collection_for_alias_finish (result, &error); g_assert_no_error (error); g_object_unref (result); collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)); g_assert_cmpstr (collection_path, ==, "/org/freedesktop/secrets/collection/english"); g_assert_cmpuint (secret_collection_get_flags (collection), ==, SECRET_COLLECTION_NONE); g_assert_null (secret_collection_get_items (collection)); g_object_unref (collection); result = NULL; secret_collection_for_alias (test->service, "unknown", SECRET_COLLECTION_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); collection = secret_collection_for_alias_finish (result, &error); g_assert_no_error (error); g_assert_null (collection); g_object_unref (result); } static void test_for_alias_load_sync (Test *test, gconstpointer used) { const gchar *collection_path; SecretCollection *collection; GError *error = NULL; GList *items; collection = secret_collection_for_alias_sync (test->service, "default", SECRET_COLLECTION_LOAD_ITEMS, NULL, &error); g_assert_no_error (error); collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)); g_assert_cmpstr (collection_path, ==, "/org/freedesktop/secrets/collection/english"); g_assert_cmpuint (secret_collection_get_flags (collection), ==, SECRET_COLLECTION_LOAD_ITEMS); items = secret_collection_get_items (collection); g_assert_nonnull (items); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_for_alias_load_async (Test *test, gconstpointer used) { const gchar *collection_path; SecretCollection *collection; GAsyncResult *result = NULL; GError *error = NULL; GList *items; secret_collection_for_alias (test->service, "default", SECRET_COLLECTION_LOAD_ITEMS, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); collection = secret_collection_for_alias_finish (result, &error); g_assert_no_error (error); g_object_unref (result); collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)); g_assert_cmpstr (collection_path, ==, "/org/freedesktop/secrets/collection/english"); g_assert_cmpuint (secret_collection_get_flags (collection), ==, SECRET_COLLECTION_LOAD_ITEMS); items = secret_collection_get_items (collection); g_assert_nonnull (items); g_list_free_full (items, g_object_unref); g_object_unref (collection); result = NULL; } #define g_assert_cmpstr_free(str1, op, str2) G_STMT_START { char *str = str1; g_assert_cmpstr (str, op, str2); g_free (str); } G_STMT_END static void test_create_sync (Test *test, gconstpointer unused) { GError *error = NULL; SecretCollection *collection; collection = secret_collection_create_sync (test->service, "Train", NULL, SECRET_COLLECTION_CREATE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (collection), (gpointer *)&collection); g_assert_true (g_str_has_prefix (g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)), "/org/freedesktop/secrets/collection")); g_assert_cmpstr_free (secret_collection_get_label (collection), ==, "Train"); g_assert_false (secret_collection_get_locked (collection)); g_object_unref (collection); g_assert_null (collection); } static void test_create_async (Test *test, gconstpointer unused) { GError *error = NULL; SecretCollection *collection; GAsyncResult *result = NULL; secret_collection_create (test->service, "Train", NULL, SECRET_COLLECTION_CREATE_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); collection = secret_collection_create_finish (result, &error); g_assert_no_error (error); g_object_unref (result); g_object_add_weak_pointer (G_OBJECT (collection), (gpointer *)&collection); g_assert_true (g_str_has_prefix (g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)), "/org/freedesktop/secrets/collection")); g_assert_cmpstr_free (secret_collection_get_label (collection), ==, "Train"); g_assert_false (secret_collection_get_locked (collection)); g_object_unref (collection); g_assert_null (collection); } static void test_properties (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; SecretService *service; GError *error = NULL; guint64 created; guint64 modified; gboolean locked; gchar *label; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); g_assert_false (secret_collection_get_locked (collection)); g_assert_cmpuint (secret_collection_get_created (collection), <=, time (NULL)); g_assert_cmpuint (secret_collection_get_modified (collection), <=, time (NULL)); label = secret_collection_get_label (collection); g_assert_cmpstr (label, ==, "Collection One"); g_free (label); g_object_get (collection, "locked", &locked, "created", &created, "modified", &modified, "label", &label, "service", &service, NULL); g_assert_false (locked); g_assert_cmpuint (created, <=, time (NULL)); g_assert_cmpuint (modified, <=, time (NULL)); g_assert_cmpstr (label, ==, "Collection One"); g_free (label); g_assert_true (service == test->service); g_object_unref (service); g_object_unref (collection); } static void check_items_equal (GList *items, ...) { GHashTable *paths; gboolean have_item; const gchar *path; guint num_items; va_list va; GList *l; va_start (va, items); paths = g_hash_table_new (g_str_hash, g_str_equal); while ((path = va_arg (va, gchar *)) != NULL) g_hash_table_insert (paths, (gpointer)path, (gpointer)path); va_end (va); num_items = g_hash_table_size (paths); g_assert_cmpuint (num_items, ==, g_list_length (items)); for (l = items; l != NULL; l = g_list_next (l)) { path = g_dbus_proxy_get_object_path (l->data); have_item = g_hash_table_remove (paths, path); g_assert_true (have_item); } g_hash_table_destroy (paths); } static void test_items (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GError *error = NULL; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_LOAD_ITEMS, NULL, &error); g_assert_no_error (error); items = secret_collection_get_items (collection); check_items_equal (items, "/org/freedesktop/secrets/collection/english/1", "/org/freedesktop/secrets/collection/english/2", "/org/freedesktop/secrets/collection/english/3", NULL); g_list_free_full (items, g_object_unref); g_object_get (collection, "items", &items, NULL); check_items_equal (items, "/org/freedesktop/secrets/collection/english/1", "/org/freedesktop/secrets/collection/english/2", "/org/freedesktop/secrets/collection/english/3", NULL); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_items_empty (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/empty"; SecretCollection *collection; GError *error = NULL; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_LOAD_ITEMS, NULL, &error); g_assert_no_error (error); items = secret_collection_get_items (collection); check_items_equal (items, NULL); g_list_free_full (items, g_object_unref); g_object_get (collection, "items", &items, NULL); check_items_equal (items, NULL); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_items_empty_async (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/empty"; SecretCollection *collection; GAsyncResult *result = NULL; GError *error = NULL; GList *items; secret_collection_new_for_dbus_path (test->service, collection_path, SECRET_COLLECTION_LOAD_ITEMS, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); collection = secret_collection_new_for_dbus_path_finish (result, &error); g_assert_no_error (error); g_object_unref (result); items = secret_collection_get_items (collection); check_items_equal (items, NULL); g_list_free_full (items, g_object_unref); g_object_get (collection, "items", &items, NULL); check_items_equal (items, NULL); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_set_label_sync (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GError *error = NULL; SecretCollection *collection; gboolean ret; gchar *label; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); label = secret_collection_get_label (collection); g_assert_cmpstr (label, ==, "Collection One"); g_free (label); ret = secret_collection_set_label_sync (collection, "Another label", NULL, &error); g_assert_no_error (error); g_assert_true (ret); label = secret_collection_get_label (collection); g_assert_cmpstr (label, ==, "Another label"); g_free (label); g_object_unref (collection); } static void test_set_label_async (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GAsyncResult *result = NULL; GError *error = NULL; SecretCollection *collection; gboolean ret; gchar *label; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); label = secret_collection_get_label (collection); g_assert_cmpstr (label, ==, "Collection One"); g_free (label); secret_collection_set_label (collection, "Another label", NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); ret = secret_collection_set_label_finish (collection, result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); label = secret_collection_get_label (collection); g_assert_cmpstr (label, ==, "Another label"); g_free (label); g_object_unref (collection); } static void test_set_label_prop (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GAsyncResult *result = NULL; GError *error = NULL; SecretCollection *collection; guint sigs = 2; gchar *label; secret_collection_new_for_dbus_path (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); collection = secret_collection_new_for_dbus_path_finish (result, &error); g_assert_no_error (error); g_object_unref (result); label = secret_collection_get_label (collection); g_assert_cmpstr (label, ==, "Collection One"); g_free (label); g_signal_connect (collection, "notify::label", G_CALLBACK (on_notify_stop), &sigs); g_object_set (collection, "label", "Blah blah", NULL); /* Wait for the property to actually 'take' */ egg_test_wait (); label = secret_collection_get_label (collection); g_assert_cmpstr (label, ==, "Blah blah"); g_free (label); g_object_unref (collection); } static void test_delete_sync (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GError *error = NULL; gboolean ret; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); ret = secret_collection_delete_sync (collection, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (collection); collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); g_assert_null (collection); g_clear_error (&error); } static void test_delete_async (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GAsyncResult *result = NULL; GError *error = NULL; gboolean ret; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); secret_collection_delete (collection, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); ret = secret_collection_delete_finish (collection, result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_true (ret); g_object_unref (collection); collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); g_assert_null (collection); g_clear_error(&error); } static void test_search_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GHashTable *attributes; GError *error = NULL; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); items = secret_collection_search_sync (collection, &MOCK_SCHEMA, attributes, SECRET_SEARCH_NONE, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_null (items->next); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_search_async (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GAsyncResult *result = NULL; GHashTable *attributes; GError *error = NULL; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); secret_collection_search (collection, &MOCK_SCHEMA, attributes, SECRET_SEARCH_NONE, NULL, on_async_result, &result); g_hash_table_unref (attributes); g_assert_null (result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); items = secret_collection_search_finish (collection, result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_null (items->next); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static gint sort_by_object_path (gconstpointer a, gconstpointer b) { const gchar *pa = g_dbus_proxy_get_object_path ((GDBusProxy *)a); const gchar *pb = g_dbus_proxy_get_object_path ((GDBusProxy *)b); return g_strcmp0 (pa, pb); } static void test_search_all_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GHashTable *attributes; GError *error = NULL; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); items = secret_collection_search_sync (collection, &MOCK_SCHEMA, attributes, SECRET_SEARCH_ALL, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); items = g_list_sort (items, sort_by_object_path); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_null (secret_item_get_secret (items->data)); g_assert_nonnull (items->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/english/2"); g_assert_null (secret_item_get_secret (items->next->data)); g_assert_nonnull (items->next->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->next->data), ==, "/org/freedesktop/secrets/collection/english/3"); g_assert_null (secret_item_get_secret (items->next->next->data)); g_assert_null (items->next->next->next); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_search_all_async (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GAsyncResult *result = NULL; GHashTable *attributes; GError *error = NULL; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); secret_collection_search (collection, &MOCK_SCHEMA, attributes, SECRET_SEARCH_ALL, NULL, on_async_result, &result); g_hash_table_unref (attributes); g_assert_null (result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); items = secret_collection_search_finish (collection, result, &error); g_assert_no_error (error); g_object_unref (result); items = g_list_sort (items, sort_by_object_path); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_null (secret_item_get_secret (items->data)); g_assert_nonnull (items->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/english/2"); g_assert_null (secret_item_get_secret (items->next->data)); g_assert_nonnull (items->next->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->next->data), ==, "/org/freedesktop/secrets/collection/english/3"); g_assert_null (secret_item_get_secret (items->next->next->data)); g_assert_null (items->next->next->next); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_search_unlock_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/spanish"; SecretCollection *collection; GHashTable *attributes; GError *error = NULL; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); items = secret_collection_search_sync (collection, &MOCK_SCHEMA, attributes, SECRET_SEARCH_UNLOCK, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_false (secret_item_get_locked (items->data)); g_assert_null (secret_item_get_secret (items->data)); g_assert_null (items->next); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_search_unlock_async (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/spanish"; SecretCollection *collection; GAsyncResult *result = NULL; GHashTable *attributes; GError *error = NULL; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); secret_collection_search (collection, &MOCK_SCHEMA, attributes, SECRET_SEARCH_UNLOCK, NULL, on_async_result, &result); g_hash_table_unref (attributes); g_assert_null (result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); items = secret_collection_search_finish (collection, result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_false (secret_item_get_locked (items->data)); g_assert_null (secret_item_get_secret (items->data)); g_assert_null (items->next); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_search_secrets_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GHashTable *attributes; GError *error = NULL; SecretValue *value; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); items = secret_collection_search_sync (collection, &MOCK_SCHEMA, attributes, SECRET_SEARCH_LOAD_SECRETS, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_false (secret_item_get_locked (items->data)); value = secret_item_get_secret (items->data); g_assert_nonnull (value); secret_value_unref (value); g_assert_null (items->next); g_list_free_full (items, g_object_unref); g_object_unref (collection); } static void test_search_secrets_async (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GAsyncResult *result = NULL; GHashTable *attributes; GError *error = NULL; SecretValue *value; GList *items; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); secret_collection_search (collection, &MOCK_SCHEMA, attributes, SECRET_SEARCH_LOAD_SECRETS, NULL, on_async_result, &result); g_hash_table_unref (attributes); g_assert_null (result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); items = secret_collection_search_finish (collection, result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_false (secret_item_get_locked (items->data)); value = secret_item_get_secret (items->data); g_assert_nonnull (value); secret_value_unref (value); g_assert_null (items->next); g_list_free_full (items, g_object_unref); g_object_unref (collection); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-collection"); g_test_add ("/collection/new-sync", Test, "mock-service-normal.py", setup, test_new_sync, teardown); g_test_add ("/collection/new-async", Test, "mock-service-normal.py", setup, test_new_async, teardown); g_test_add ("/collection/new-sync-noexist", Test, "mock-service-normal.py", setup, test_new_sync_noexist, teardown); g_test_add ("/collection/new-async-noexist", Test, "mock-service-normal.py", setup, test_new_async_noexist, teardown); g_test_add ("/collection/for-alias-sync", Test, "mock-service-normal.py", setup, test_for_alias_sync, teardown); g_test_add ("/collection/for-alias-async", Test, "mock-service-normal.py", setup, test_for_alias_async, teardown); g_test_add ("/collection/for-alias-load-sync", Test, "mock-service-normal.py", setup, test_for_alias_load_sync, teardown); g_test_add ("/collection/for-alias-load-async", Test, "mock-service-normal.py", setup, test_for_alias_load_async, teardown); g_test_add ("/collection/create-sync", Test, "mock-service-normal.py", setup, test_create_sync, teardown); g_test_add ("/collection/create-async", Test, "mock-service-normal.py", setup, test_create_async, teardown); g_test_add ("/collection/properties", Test, "mock-service-normal.py", setup, test_properties, teardown); g_test_add ("/collection/items", Test, "mock-service-normal.py", setup, test_items, teardown); g_test_add ("/collection/items-empty", Test, "mock-service-normal.py", setup, test_items_empty, teardown); g_test_add ("/collection/items-empty-async", Test, "mock-service-normal.py", setup, test_items_empty_async, teardown); g_test_add ("/collection/set-label-sync", Test, "mock-service-normal.py", setup, test_set_label_sync, teardown); g_test_add ("/collection/set-label-async", Test, "mock-service-normal.py", setup, test_set_label_async, teardown); g_test_add ("/collection/set-label-prop", Test, "mock-service-normal.py", setup, test_set_label_prop, teardown); g_test_add ("/collection/delete-sync", Test, "mock-service-normal.py", setup, test_delete_sync, teardown); g_test_add ("/collection/delete-async", Test, "mock-service-normal.py", setup, test_delete_async, teardown); g_test_add ("/collection/search-sync", Test, "mock-service-normal.py", setup, test_search_sync, teardown); g_test_add ("/collection/search-async", Test, "mock-service-normal.py", setup, test_search_async, teardown); g_test_add ("/collection/search-all-sync", Test, "mock-service-normal.py", setup, test_search_all_sync, teardown); g_test_add ("/collection/search-all-async", Test, "mock-service-normal.py", setup, test_search_all_async, teardown); g_test_add ("/collection/search-unlock-sync", Test, "mock-service-normal.py", setup, test_search_unlock_sync, teardown); g_test_add ("/collection/search-unlock-async", Test, "mock-service-normal.py", setup, test_search_unlock_async, teardown); g_test_add ("/collection/search-secrets-sync", Test, "mock-service-normal.py", setup, test_search_secrets_sync, teardown); g_test_add ("/collection/search-secrets-async", Test, "mock-service-normal.py", setup, test_search_secrets_async, teardown); return egg_tests_run_with_loop (); } 07070100000082000081A400000000000000000000000167D9F0D9000027C8000000000000000000000000000000000000003200000000libsecret-0.21.7/libsecret/test-file-collection.c #include "config.h" #undef G_DISABLE_ASSERT #include "egg/egg-testing.h" #include "secret-file-collection.h" #include "secret-retrievable.h" #include "secret-schema.h" #include typedef struct { gchar *directory; GMainLoop *loop; SecretFileCollection *collection; } Test; static void on_new_async (GObject *source_object, GAsyncResult *result, gpointer user_data) { Test *test = user_data; GObject *object; GError *error = NULL; object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, &error); test->collection = SECRET_FILE_COLLECTION (object); g_main_loop_quit (test->loop); g_assert_no_error (error); } static void setup (Test *test, gconstpointer data) { GFile *file; gchar *path; SecretValue *password; gchar *fixture = NULL; if (data != NULL) fixture = g_build_filename (SRCDIR, "libsecret", "fixtures", data, NULL); test->directory = egg_tests_create_scratch_directory (fixture, NULL); g_free (fixture); test->loop = g_main_loop_new (NULL, TRUE); path = g_build_filename (test->directory, "default.keyring", NULL); file = g_file_new_for_path (path); g_free (path); password = secret_value_new ("password", -1, "text/plain"); g_async_initable_new_async (SECRET_TYPE_FILE_COLLECTION, G_PRIORITY_DEFAULT, NULL, on_new_async, test, "file", file, "password", password, NULL); g_object_unref (file); secret_value_unref (password); g_main_loop_run (test->loop); } static void teardown (Test *test, gconstpointer unused) { egg_tests_remove_scratch_directory (test->directory); g_free (test->directory); g_clear_object (&test->collection); g_main_loop_unref (test->loop); } static void test_init (Test *test, gconstpointer unused) { } static void test_replace (Test *test, gconstpointer unused) { GHashTable *attributes; SecretValue *value; GError *error = NULL; gboolean ret; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (attributes, g_strdup ("foo"), g_strdup ("a")); g_hash_table_insert (attributes, g_strdup ("bar"), g_strdup ("b")); g_hash_table_insert (attributes, g_strdup ("baz"), g_strdup ("c")); value = secret_value_new ("test1", -1, "text/plain"); ret = secret_file_collection_replace (test->collection, attributes, "label", value, &error); g_assert_no_error (error); g_assert_true (ret); secret_value_unref (value); value = secret_value_new ("test2", -1, "text/plain"); ret = secret_file_collection_replace (test->collection, attributes, "label", value, &error); g_assert_no_error (error); g_assert_true (ret); secret_value_unref (value); g_hash_table_unref (attributes); } static void test_clear (Test *test, gconstpointer unused) { GHashTable *attributes; SecretValue *value; GError *error = NULL; gboolean ret; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (attributes, g_strdup ("foo"), g_strdup ("a")); g_hash_table_insert (attributes, g_strdup ("bar"), g_strdup ("b")); g_hash_table_insert (attributes, g_strdup ("baz"), g_strdup ("c")); value = secret_value_new ("test1", -1, "text/plain"); ret = secret_file_collection_replace (test->collection, attributes, "label", value, &error); g_assert_no_error (error); g_assert_true (ret); secret_value_unref (value); ret = secret_file_collection_clear (test->collection, attributes, &error); g_assert_no_error (error); g_assert_true (ret); g_hash_table_unref (attributes); } static void test_search (Test *test, gconstpointer unused) { GHashTable *attributes; SecretValue *value; GError *error = NULL; GList *matches; gboolean ret; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (attributes, g_strdup ("foo"), g_strdup ("a")); g_hash_table_insert (attributes, g_strdup ("bar"), g_strdup ("b")); g_hash_table_insert (attributes, g_strdup ("baz"), g_strdup ("c")); value = secret_value_new ("test1", -1, "text/plain"); ret = secret_file_collection_replace (test->collection, attributes, "label", value, &error); g_assert_no_error (error); g_assert_true (ret); secret_value_unref (value); g_hash_table_remove (attributes, "foo"); value = secret_value_new ("test2", -1, "text/plain"); ret = secret_file_collection_replace (test->collection, attributes, "label", value, &error); g_assert_no_error (error); g_assert_true (ret); secret_value_unref (value); matches = secret_file_collection_search (test->collection, attributes); g_assert_cmpint (g_list_length (matches), ==, 2); g_list_free_full (matches, (GDestroyNotify)g_variant_unref); g_hash_table_unref (attributes); } static void test_decrypt (Test *test, gconstpointer unused) { GHashTable *attributes; SecretValue *value; GError *error = NULL; GList *matches; SecretFileItem *item; const gchar *secret; gsize n_secret; gchar *label; gboolean ret; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (attributes, g_strdup ("foo"), g_strdup ("a")); g_hash_table_insert (attributes, g_strdup ("bar"), g_strdup ("b")); g_hash_table_insert (attributes, g_strdup ("baz"), g_strdup ("c")); value = secret_value_new ("test1", -1, "text/plain"); ret = secret_file_collection_replace (test->collection, attributes, "label", value, &error); g_assert_no_error (error); g_assert_true (ret); secret_value_unref (value); matches = secret_file_collection_search (test->collection, attributes); g_assert_cmpint (g_list_length (matches), ==, 1); item = _secret_file_item_decrypt ((GVariant *)matches->data, test->collection, &error); g_list_free_full (matches, (GDestroyNotify)g_variant_unref); g_assert_no_error (error); g_assert_nonnull (item); g_object_get (item, "label", &label, NULL); g_assert_cmpstr (label, ==, "label"); g_free (label); value = secret_retrievable_retrieve_secret_sync (SECRET_RETRIEVABLE (item), NULL, &error); g_assert_no_error (error); secret = secret_value_get (value, &n_secret); g_assert_cmpstr (secret, ==, "test1"); secret_value_unref (value); g_object_unref (item); g_hash_table_unref (attributes); } static void on_write (GObject *source_object, GAsyncResult *result, gpointer user_data) { SecretFileCollection *collection = SECRET_FILE_COLLECTION (source_object); Test *test = user_data; GError *error = NULL; gboolean ret; ret = secret_file_collection_write_finish (collection, result, &error); g_assert_no_error (error); g_assert_true (ret); g_main_loop_quit (test->loop); } static void test_write (Test *test, gconstpointer unused) { GHashTable *attributes; SecretValue *value; GError *error = NULL; gboolean ret; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (attributes, g_strdup ("foo"), g_strdup ("a")); g_hash_table_insert (attributes, g_strdup ("bar"), g_strdup ("b")); g_hash_table_insert (attributes, g_strdup ("baz"), g_strdup ("c")); value = secret_value_new ("test1", -1, "text/plain"); ret = secret_file_collection_replace (test->collection, attributes, "label1", value, &error); g_assert_no_error (error); g_assert_true (ret); secret_value_unref (value); g_hash_table_unref (attributes); attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (attributes, g_strdup ("apple"), g_strdup ("a")); g_hash_table_insert (attributes, g_strdup ("orange"), g_strdup ("b")); g_hash_table_insert (attributes, g_strdup ("banana"), g_strdup ("c")); value = secret_value_new ("test1", -1, "text/plain"); ret = secret_file_collection_replace (test->collection, attributes, "label2", value, &error); g_assert_no_error (error); g_assert_true (ret); secret_value_unref (value); g_hash_table_unref (attributes); secret_file_collection_write (test->collection, NULL, on_write, test); g_main_loop_run (test->loop); } static void test_read (Test *test, gconstpointer unused) { GHashTable *attributes; SecretValue *value; GError *error = NULL; GList *matches; SecretFileItem *item; const gchar *secret; gsize n_secret; gchar *label; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (attributes, g_strdup ("foo"), g_strdup ("a")); matches = secret_file_collection_search (test->collection, attributes); g_assert_cmpint (g_list_length (matches), ==, 1); item = _secret_file_item_decrypt ((GVariant *)matches->data, test->collection, &error); g_list_free_full (matches, (GDestroyNotify)g_variant_unref); g_assert_no_error (error); g_assert_nonnull (item); g_object_get (item, "label", &label, NULL); g_assert_cmpstr (label, ==, "label1"); g_free (label); value = secret_retrievable_retrieve_secret_sync (SECRET_RETRIEVABLE (item), NULL, &error); g_assert_no_error (error); secret = secret_value_get (value, &n_secret); g_assert_cmpstr (secret, ==, "test1"); secret_value_unref (value); g_object_unref (item); g_hash_table_unref (attributes); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-file-collection"); g_test_add ("/file-collection/init", Test, NULL, setup, test_init, teardown); g_test_add ("/file-collection/replace", Test, NULL, setup, test_replace, teardown); g_test_add ("/file-collection/clear", Test, NULL, setup, test_clear, teardown); g_test_add ("/file-collection/search", Test, NULL, setup, test_search, teardown); g_test_add ("/file-collection/decrypt", Test, NULL, setup, test_decrypt, teardown); g_test_add ("/file-collection/write", Test, NULL, setup, test_write, teardown); g_test_add ("/file-collection/read", Test, "default.keyring", setup, test_read, teardown); return egg_tests_run_with_loop (); } 07070100000083000081A400000000000000000000000167D9F0D900006D3B000000000000000000000000000000000000002700000000libsecret-0.21.7/libsecret/test-item.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-collection.h" #include "secret-item.h" #include "secret-service.h" #include "secret-paths.h" #include "secret-private.h" #include "mock-service.h" #include "egg/egg-testing.h" #include #include #include static const SecretSchema MOCK_SCHEMA = { "org.mock.Schema.Item", SECRET_SCHEMA_NONE, { { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, } }; typedef struct { SecretService *service; } Test; static void setup (Test *test, gconstpointer data) { GError *error = NULL; const gchar *mock_script = data; mock_service_start (mock_script, &error); g_assert_no_error (error); test->service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (test->service), (gpointer *)&test->service); } static void teardown (Test *test, gconstpointer unused) { g_object_unref (test->service); secret_service_disconnect (); g_assert_null (test->service); mock_service_stop (); } static void on_async_result (GObject *source, GAsyncResult *result, gpointer user_data) { GAsyncResult **ret = user_data; g_assert_nonnull (ret); g_assert_null (*ret); *ret = g_object_ref (result); egg_test_wait_stop (); } static void on_notify_stop (GObject *obj, GParamSpec *spec, gpointer user_data) { guint *sigs = user_data; g_assert_nonnull (sigs); g_assert_true (*sigs > 0); if (--(*sigs) == 0) egg_test_wait_stop (); } static void test_new_sync (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GError *error = NULL; SecretItem *item; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); g_assert_cmpstr (g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)), ==, item_path); g_object_unref (item); } static void test_new_sync_noexist (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/0000"; GError *error = NULL; SecretItem *item; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); g_assert_null (item); g_clear_error (&error); } static void test_new_async (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GAsyncResult *result = NULL; GError *error = NULL; SecretItem *item; secret_item_new_for_dbus_path (test->service, item_path, SECRET_ITEM_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); item = secret_item_new_for_dbus_path_finish (result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_cmpstr (g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)), ==, item_path); g_object_unref (item); } static void test_new_async_noexist (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/0000"; GAsyncResult *result = NULL; GError *error = NULL; SecretItem *item; secret_item_new_for_dbus_path (test->service, item_path, SECRET_ITEM_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); item = secret_item_new_for_dbus_path_finish (result, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); g_assert_null (item); g_clear_error (&error); g_object_unref (result); } #define g_assert_cmpstr_free(str1, op, str2) G_STMT_START { char *str = str1; g_assert_cmpstr (str, op, str2); g_free (str); } G_STMT_END static void test_create_sync (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GError *error = NULL; SecretItem *item; GHashTable *attributes; SecretValue *value; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "even", "true"); g_hash_table_insert (attributes, "string", "ten"); g_hash_table_insert (attributes, "number", "10"); value = secret_value_new ("Hoohah", -1, "text/plain"); item = secret_item_create_sync (collection, &MOCK_SCHEMA, attributes, "Tunnel", value, SECRET_ITEM_CREATE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (item), (gpointer *)&item); g_hash_table_unref (attributes); g_object_unref (collection); secret_value_unref (value); g_assert_true (g_str_has_prefix (g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)), collection_path)); g_assert_cmpstr_free (secret_item_get_label (item), ==, "Tunnel"); g_assert_false (secret_item_get_locked (item)); g_object_unref (item); g_assert_null (item); } static void test_create_async (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretCollection *collection; GAsyncResult *result = NULL; GError *error = NULL; SecretItem *item; GHashTable *attributes; SecretValue *value; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "even", "true"); g_hash_table_insert (attributes, "string", "ten"); g_hash_table_insert (attributes, "number", "10"); value = secret_value_new ("Hoohah", -1, "text/plain"); secret_item_create (collection, &MOCK_SCHEMA, attributes, "Tunnel", value, SECRET_ITEM_CREATE_NONE, NULL, on_async_result, &result); g_assert_no_error (error); g_hash_table_unref (attributes); g_object_unref (collection); secret_value_unref (value); egg_test_wait (); item = secret_item_create_finish (result, &error); g_assert_no_error (error); g_object_unref (result); g_object_add_weak_pointer (G_OBJECT (item), (gpointer *)&item); g_assert_true (g_str_has_prefix (g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)), collection_path)); g_assert_cmpstr_free (secret_item_get_label (item), ==, "Tunnel"); g_assert_false (secret_item_get_locked (item)); g_object_unref (item); g_assert_null (item); } static void test_properties (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GError *error = NULL; GHashTable *attributes; SecretService *service; SecretItem *item; guint64 created; guint64 modified; gboolean locked; gchar *label; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); g_assert_false (secret_item_get_locked (item)); g_assert_cmpuint (secret_item_get_created (item), <=, time (NULL)); g_assert_cmpuint (secret_item_get_modified (item), <=, time (NULL)); label = secret_item_get_label (item); g_assert_cmpstr (label, ==, "Item One"); g_free (label); attributes = secret_item_get_attributes (item); g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one"); g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1"); g_assert_cmpstr (g_hash_table_lookup (attributes, "even"), ==, "false"); g_assert_cmpuint (g_hash_table_size (attributes), ==, 4); g_hash_table_unref (attributes); g_object_get (item, "locked", &locked, "created", &created, "modified", &modified, "label", &label, "attributes", &attributes, "service", &service, NULL); g_assert_false (locked); g_assert_cmpuint (created, <=, time (NULL)); g_assert_cmpuint (modified, <=, time (NULL)); g_assert_cmpstr (label, ==, "Item One"); g_free (label); g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one"); g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1"); g_assert_cmpstr (g_hash_table_lookup (attributes, "even"), ==, "false"); g_assert_cmpuint (g_hash_table_size (attributes), ==, 4); g_hash_table_unref (attributes); g_assert_true (service == test->service); g_object_unref (service); g_object_unref (item); } static void test_set_label_sync (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GError *error = NULL; SecretItem *item; gboolean ret; gchar *label; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); label = secret_item_get_label (item); g_assert_cmpstr (label, ==, "Item One"); g_free (label); ret = secret_item_set_label_sync (item, "Another label", NULL, &error); g_assert_no_error (error); g_assert_true (ret); label = secret_item_get_label (item); g_assert_cmpstr (label, ==, "Another label"); g_free (label); g_object_unref (item); } static void test_set_label_async (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GAsyncResult *result = NULL; GError *error = NULL; SecretItem *item; gboolean ret; gchar *label; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); label = secret_item_get_label (item); g_assert_cmpstr (label, ==, "Item One"); g_free (label); secret_item_set_label (item, "Another label", NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); ret = secret_item_set_label_finish (item, result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); label = secret_item_get_label (item); g_assert_cmpstr (label, ==, "Another label"); g_free (label); g_object_unref (item); } static void test_set_label_prop (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GAsyncResult *result = NULL; GError *error = NULL; SecretItem *item; guint sigs = 2; gchar *label; secret_item_new_for_dbus_path (test->service, item_path, SECRET_ITEM_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); item = secret_item_new_for_dbus_path_finish (result, &error); g_assert_no_error (error); g_object_unref (result); label = secret_item_get_label (item); g_assert_cmpstr (label, ==, "Item One"); g_free (label); g_signal_connect (item, "notify::label", G_CALLBACK (on_notify_stop), &sigs); g_object_set (item, "label", "Blah blah", NULL); /* Wait for the property to actually 'take' */ egg_test_wait (); label = secret_item_get_label (item); g_assert_cmpstr (label, ==, "Blah blah"); g_free (label); g_object_add_weak_pointer (G_OBJECT (item), (gpointer *)&item); g_object_unref (item); while (item != NULL) g_main_context_iteration (g_main_context_get_thread_default (), TRUE); } static void test_set_attributes_sync (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GError *error = NULL; SecretItem *item; gboolean ret; GHashTable *attributes; gchar *schema_name; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); attributes = secret_item_get_attributes (item); g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one"); g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1"); g_assert_cmpstr (g_hash_table_lookup (attributes, "even"), ==, "false"); g_assert_cmpuint (g_hash_table_size (attributes), ==, 4); g_hash_table_unref (attributes); /* Has some other schema */ schema_name = secret_item_get_schema_name (item); g_assert_cmpstr (schema_name, !=, MOCK_SCHEMA.name); g_free (schema_name); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "string", "five"); g_hash_table_insert (attributes, "number", "5"); ret = secret_item_set_attributes_sync (item, &MOCK_SCHEMA, attributes, NULL, &error); g_hash_table_unref (attributes); g_assert_no_error (error); g_assert_true (ret); attributes = secret_item_get_attributes (item); g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "five"); g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "5"); g_assert_cmpuint (g_hash_table_size (attributes), ==, 3); g_hash_table_unref (attributes); /* Now has our schema */ schema_name = secret_item_get_schema_name (item); g_assert_cmpstr (schema_name, ==, MOCK_SCHEMA.name); g_free (schema_name); g_object_unref (item); } static void test_set_attributes_async (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GHashTable *attributes; GError *error = NULL; GAsyncResult *result = NULL; SecretItem *item; gchar *schema_name; gboolean ret; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); attributes = secret_item_get_attributes (item); g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one"); g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1"); g_assert_cmpstr (g_hash_table_lookup (attributes, "even"), ==, "false"); g_assert_cmpuint (g_hash_table_size (attributes), ==, 4); g_hash_table_unref (attributes); /* Has some other schema */ schema_name = secret_item_get_schema_name (item); g_assert_cmpstr (schema_name, !=, MOCK_SCHEMA.name); g_free (schema_name); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "string", "five"); g_hash_table_insert (attributes, "number", "5"); secret_item_set_attributes (item, &MOCK_SCHEMA, attributes, NULL, on_async_result, &result); g_assert_null (result); g_hash_table_unref (attributes); egg_test_wait (); ret = secret_item_set_attributes_finish (item, result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); attributes = secret_item_get_attributes (item); g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "five"); g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "5"); g_assert_cmpuint (g_hash_table_size (attributes), ==, 3); g_hash_table_unref (attributes); /* Now has our schema */ schema_name = secret_item_get_schema_name (item); g_assert_cmpstr (schema_name, ==, MOCK_SCHEMA.name); g_free (schema_name); g_object_unref (item); } static void test_set_attributes_prop (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GAsyncResult *result = NULL; GError *error = NULL; SecretItem *item; GHashTable *attributes; guint sigs = 2; secret_item_new_for_dbus_path (test->service, item_path, SECRET_ITEM_NONE, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); item = secret_item_new_for_dbus_path_finish (result, &error); g_assert_no_error (error); g_object_unref (result); attributes = secret_item_get_attributes (item); g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one"); g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1"); g_assert_cmpstr (g_hash_table_lookup (attributes, "even"), ==, "false"); g_assert_cmpuint (g_hash_table_size (attributes), ==, 4); g_hash_table_unref (attributes); g_signal_connect (item, "notify::attributes", G_CALLBACK (on_notify_stop), &sigs); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "string", "five"); g_hash_table_insert (attributes, "number", "5"); g_object_set (item, "attributes", attributes, NULL); g_hash_table_unref (attributes); /* Wait for the property to actually 'take' */ egg_test_wait (); attributes = secret_item_get_attributes (item); g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "five"); g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "5"); g_assert_cmpuint (g_hash_table_size (attributes), ==, 2); g_hash_table_unref (attributes); g_object_add_weak_pointer (G_OBJECT (item), (gpointer *)&item); g_object_unref (item); while (item != NULL) g_main_context_iteration (g_main_context_get_thread_default (), TRUE); } static void test_load_secret_sync (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GError *error = NULL; SecretItem *item; SecretValue *value; gconstpointer data; gboolean ret; gsize length; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); value = secret_item_get_secret (item); g_assert_null (value); ret = secret_item_load_secret_sync (item, NULL, &error); g_assert_no_error (error); g_assert_true (ret); value = secret_item_get_secret (item); g_assert_nonnull (value); data = secret_value_get (value, &length); egg_assert_cmpmem (data, length, ==, "111", 3); secret_value_unref (value); g_object_unref (item); } static void test_load_secret_async (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GAsyncResult *result = NULL; GError *error = NULL; SecretItem *item; SecretValue *value; gconstpointer data; gboolean ret; gsize length; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); value = secret_item_get_secret (item); g_assert_null (value); secret_item_load_secret (item, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); ret = secret_item_load_secret_finish (item, result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); value = secret_item_get_secret (item); g_assert_nonnull (value); data = secret_value_get (value, &length); egg_assert_cmpmem (data, length, ==, "111", 3); secret_value_unref (value); g_object_unref (item); } static void test_set_secret_sync (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GError *error = NULL; SecretItem *item; gconstpointer data; SecretValue *value; SecretValue *check; gboolean ret; gsize length; value = secret_value_new ("Sinking", -1, "strange/content-type"); item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); ret = secret_item_set_secret_sync (item, value, NULL, &error); g_assert_no_error (error); g_assert_true (ret); check = secret_item_get_secret (item); g_assert_true (check == value); secret_value_unref (check); secret_value_unref (value); ret = secret_item_load_secret_sync (item, NULL, &error); g_assert_no_error (error); g_assert_true (ret); value = secret_item_get_secret (item); g_assert_nonnull (value); data = secret_value_get (value, &length); egg_assert_cmpmem (data, length, ==, "Sinking", 7); g_assert_cmpstr (secret_value_get_content_type (value), ==, "strange/content-type"); secret_value_unref (value); g_object_unref (item); } static void test_secrets_sync (Test *test, gconstpointer used) { const gchar *path_item_one = "/org/freedesktop/secrets/collection/english/1"; const gchar *path_item_two = "/org/freedesktop/secrets/collection/english/2"; const gchar *path_item_three = "/org/freedesktop/secrets/collection/spanish/10"; SecretValue *value; GError *error = NULL; const gchar *password; SecretItem *item_one, *item_two, *item_three; GList *items = NULL; gboolean ret; gsize length; item_one = secret_item_new_for_dbus_path_sync (test->service, path_item_one, SECRET_ITEM_NONE, NULL, &error); item_two = secret_item_new_for_dbus_path_sync (test->service, path_item_two, SECRET_ITEM_NONE, NULL, &error); item_three = secret_item_new_for_dbus_path_sync (test->service, path_item_three, SECRET_ITEM_NONE, NULL, &error); items = g_list_append (items, item_one); items = g_list_append (items, item_two); items = g_list_append (items, item_three); ret = secret_item_load_secrets_sync (items, NULL, &error); g_assert_no_error (error); g_assert_true (ret); value = secret_item_get_secret (item_one); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "111"); secret_value_unref (value); value = secret_item_get_secret (item_two); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "222"); secret_value_unref (value); value = secret_item_get_secret (item_three); g_assert_null (value); g_list_free_full (items, g_object_unref); } static void test_secrets_async (Test *test, gconstpointer used) { const gchar *path_item_one = "/org/freedesktop/secrets/collection/english/1"; const gchar *path_item_two = "/org/freedesktop/secrets/collection/english/2"; const gchar *path_item_three = "/org/freedesktop/secrets/collection/spanish/10"; SecretValue *value; GError *error = NULL; const gchar *password; GAsyncResult *result = NULL; SecretItem *item_one, *item_two, *item_three; GList *items = NULL; gsize length; gboolean ret; item_one = secret_item_new_for_dbus_path_sync (test->service, path_item_one, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); item_two = secret_item_new_for_dbus_path_sync (test->service, path_item_two, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); item_three = secret_item_new_for_dbus_path_sync (test->service, path_item_three, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); items = g_list_append (items, item_one); items = g_list_append (items, item_two); items = g_list_append (items, item_three); secret_item_load_secrets (items, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); ret = secret_item_load_secrets_finish (result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_true (ret); value = secret_item_get_secret (item_one); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "111"); secret_value_unref (value); value = secret_item_get_secret (item_two); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "222"); secret_value_unref (value); value = secret_item_get_secret (item_three); g_assert_null (value); g_object_unref (item_one); g_object_unref (item_two); g_object_unref (item_three); g_list_free (items); } static void test_delete_sync (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GError *error = NULL; SecretItem *item; gboolean ret; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); ret = secret_item_delete_sync (item, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (item); item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); g_assert_null (item); g_clear_error (&error); } static void test_delete_async (Test *test, gconstpointer unused) { const gchar *item_path = "/org/freedesktop/secrets/collection/english/1"; GAsyncResult *result = NULL; GError *error = NULL; SecretItem *item; gboolean ret; item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_no_error (error); secret_item_delete (item, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); ret = secret_item_delete_finish (item, result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); g_object_unref (item); item = secret_item_new_for_dbus_path_sync (test->service, item_path, SECRET_ITEM_NONE, NULL, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); g_assert_null (item); g_clear_error (&error); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-item"); g_test_add ("/item/new-sync", Test, "mock-service-normal.py", setup, test_new_sync, teardown); g_test_add ("/item/new-async", Test, "mock-service-normal.py", setup, test_new_async, teardown); g_test_add ("/item/new-sync-noexist", Test, "mock-service-normal.py", setup, test_new_sync_noexist, teardown); g_test_add ("/item/new-async-noexist", Test, "mock-service-normal.py", setup, test_new_async_noexist, teardown); g_test_add ("/item/create-sync", Test, "mock-service-normal.py", setup, test_create_sync, teardown); g_test_add ("/item/create-async", Test, "mock-service-normal.py", setup, test_create_async, teardown); g_test_add ("/item/properties", Test, "mock-service-normal.py", setup, test_properties, teardown); g_test_add ("/item/set-label-sync", Test, "mock-service-normal.py", setup, test_set_label_sync, teardown); g_test_add ("/item/set-label-async", Test, "mock-service-normal.py", setup, test_set_label_async, teardown); g_test_add ("/item/set-label-prop", Test, "mock-service-normal.py", setup, test_set_label_prop, teardown); g_test_add ("/item/set-attributes-sync", Test, "mock-service-normal.py", setup, test_set_attributes_sync, teardown); g_test_add ("/item/set-attributes-async", Test, "mock-service-normal.py", setup, test_set_attributes_async, teardown); g_test_add ("/item/set-attributes-prop", Test, "mock-service-normal.py", setup, test_set_attributes_prop, teardown); g_test_add ("/item/load-secret-sync", Test, "mock-service-normal.py", setup, test_load_secret_sync, teardown); g_test_add ("/item/load-secret-async", Test, "mock-service-normal.py", setup, test_load_secret_async, teardown); g_test_add ("/item/set-secret-sync", Test, "mock-service-normal.py", setup, test_set_secret_sync, teardown); g_test_add ("/item/secrets-sync", Test, "mock-service-normal.py", setup, test_secrets_sync, teardown); g_test_add ("/item/secrets-async", Test, "mock-service-normal.py", setup, test_secrets_async, teardown); g_test_add ("/item/delete-sync", Test, "mock-service-normal.py", setup, test_delete_sync, teardown); g_test_add ("/item/delete-async", Test, "mock-service-normal.py", setup, test_delete_async, teardown); return egg_tests_run_with_loop (); } 07070100000084000081A400000000000000000000000167D9F0D900000924000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/test-js-clear.js/* * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. */ const Mock = imports.gi.MockService; const Secret = imports.gi.Secret; const GLib = imports.gi.GLib; const JsUnit = imports.jsUnit; const assertEquals = JsUnit.assertEquals; const assertRaises = JsUnit.assertRaises; const assertTrue = JsUnit.assertTrue; Mock.start("mock-service-normal.py"); const STORE_SCHEMA = new Secret.Schema("org.mock.Schema", Secret.SchemaFlags.NONE, { "number": Secret.SchemaAttributeType.INTEGER, "string": Secret.SchemaAttributeType.STRING, "even": Secret.SchemaAttributeType.BOOLEAN, } ); /* Synchronous */ /* var attributes = { "number": "1", "string": "one", "even": "false" }; var password = Secret.password_lookup_sync (STORE_SCHEMA, attributes, null); assertEquals("111", password); var deleted = Secret.password_clear_sync (STORE_SCHEMA, attributes, null); assertEquals(true, deleted); var password = Secret.password_lookup_sync (STORE_SCHEMA, attributes, null); assertEquals(null, password); var deleted = Secret.password_clear_sync (STORE_SCHEMA, attributes, null); assertEquals(false, deleted); */ /* Asynchronous */ var attributes = { "number": "2", "string": "two", "even": "true" }; var password = Secret.password_lookup_sync (STORE_SCHEMA, attributes, null); assertEquals("222", password); var loop = new GLib.MainLoop(null, false); Secret.password_clear (STORE_SCHEMA, attributes, null, function(source, result) { loop.quit(); var deleted = Secret.password_clear_finish(result); assertEquals(true, deleted); }); loop.run(); var password = Secret.password_lookup_sync (STORE_SCHEMA, attributes, null); assertEquals(null, password); Secret.password_clear (STORE_SCHEMA, attributes, null, function(source, result) { loop.quit(); var deleted = Secret.password_clear_finish(result); assertEquals(false, deleted); }); loop.run(); var password = Secret.password_lookup_sync (STORE_SCHEMA, attributes, null); assertEquals(null, password); Secret.Service.disconnect(); Mock.stop(); 07070100000085000081A400000000000000000000000167D9F0D9000006E3000000000000000000000000000000000000002D00000000libsecret-0.21.7/libsecret/test-js-lookup.js/* * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. */ const Mock = imports.gi.MockService; const Secret = imports.gi.Secret; const GLib = imports.gi.GLib; const JsUnit = imports.jsUnit; const assertEquals = JsUnit.assertEquals; const assertRaises = JsUnit.assertRaises; const assertTrue = JsUnit.assertTrue; Mock.start("mock-service-normal.py"); const STORE_SCHEMA = new Secret.Schema("org.mock.Schema", Secret.SchemaFlags.NONE, { "number": Secret.SchemaAttributeType.INTEGER, "string": Secret.SchemaAttributeType.STRING, "even": Secret.SchemaAttributeType.BOOLEAN, } ); /* Synchronous */ var password = Secret.password_lookup_sync (STORE_SCHEMA, { "number": "1", "even": "false" }, null); assertEquals("111", password); var password = Secret.password_lookup_sync (STORE_SCHEMA, { "number": "5", "even": "true" }, null); assertEquals(null, password); /* Asynchronous */ var loop = new GLib.MainLoop(null, false); Secret.password_lookup (STORE_SCHEMA, { "number": "2", "string": "two" }, null, function(source, result) { loop.quit(); var password = Secret.password_lookup_finish(result); assertEquals("222", password); }); loop.run(); Secret.password_lookup (STORE_SCHEMA, { "number": "7", "string": "five" }, null, function(source, result) { loop.quit(); var password = Secret.password_lookup_finish(result); assertEquals(null, password); }); loop.run(); Secret.Service.disconnect(); Mock.stop(); 07070100000086000081A400000000000000000000000167D9F0D9000007FD000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/test-js-store.js/* * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. */ const Mock = imports.gi.MockService; const Secret = imports.gi.Secret; const GLib = imports.gi.GLib; const JsUnit = imports.jsUnit; const assertEquals = JsUnit.assertEquals; const assertRaises = JsUnit.assertRaises; const assertTrue = JsUnit.assertTrue; Mock.start("mock-service-normal.py"); const STORE_SCHEMA = new Secret.Schema("org.mock.Schema", Secret.SchemaFlags.NONE, { "number": Secret.SchemaAttributeType.INTEGER, "string": Secret.SchemaAttributeType.STRING, "even": Secret.SchemaAttributeType.BOOLEAN, } ); /* Synchronous */ var attributes = { "number": "9", "string": "nine", "even": "false" }; var password = Secret.password_lookup_sync (STORE_SCHEMA, attributes, null); assertEquals(null, password); var stored = Secret.password_store_sync (STORE_SCHEMA, attributes, Secret.COLLECTION_DEFAULT, "The number nine", "999", null); assertEquals(true, stored); var password = Secret.password_lookup_sync (STORE_SCHEMA, attributes, null); assertEquals("999", password); /* Asynchronous */ var attributes = { "number": "888", "string": "eight", "even": "true" }; var password = Secret.password_lookup_sync (STORE_SCHEMA, attributes, null); assertEquals(null, password); var loop = new GLib.MainLoop(null, false); Secret.password_store (STORE_SCHEMA, attributes, null, "The number eight", "888", null, function(source, result) { loop.quit(); var stored = Secret.password_store_finish(result); assertEquals(true, stored); }); loop.run(); var password = Secret.password_lookup_sync (STORE_SCHEMA, attributes, null); assertEquals("888", password); Secret.Service.disconnect(); Mock.stop(); 07070100000087000081A400000000000000000000000167D9F0D900007E01000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/test-methods.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-attributes.h" #include "secret-collection.h" #include "secret-item.h" #include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "mock-service.h" #include "egg/egg-testing.h" #include #include #include static const SecretSchema MOCK_SCHEMA = { "org.mock.Schema", SECRET_SCHEMA_NONE, { { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, } }; static const SecretSchema NO_NAME_SCHEMA = { "unused.Schema.Name", SECRET_SCHEMA_DONT_MATCH_NAME, { { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, } }; typedef struct { SecretService *service; } Test; static void setup_mock (Test *test, gconstpointer data) { GError *error = NULL; const gchar *mock_script = data; mock_service_start (mock_script, &error); g_assert_no_error (error); } static void setup (Test *test, gconstpointer data) { GError *error = NULL; setup_mock (test, data); test->service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (test->service), (gpointer *)&test->service); } static void teardown_mock (Test *test, gconstpointer unused) { secret_service_disconnect (); mock_service_stop (); } static void teardown (Test *test, gconstpointer unused) { egg_test_wait_idle (); g_object_unref (test->service); secret_service_disconnect (); g_assert_null (test->service); teardown_mock (test, unused); } static void on_complete_get_result (GObject *source, GAsyncResult *result, gpointer user_data) { GAsyncResult **ret = user_data; g_assert_nonnull (ret); g_assert_null (*ret); *ret = g_object_ref (result); egg_test_wait_stop (); } static void test_search_sync (Test *test, gconstpointer used) { GHashTable *attributes; GError *error = NULL; GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); items = secret_service_search_sync (test->service, &MOCK_SCHEMA, attributes, SECRET_SEARCH_NONE, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_null (items->next); g_list_free_full (items, g_object_unref); } static void test_search_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GHashTable *attributes; GError *error = NULL; GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); secret_service_search (test->service, &MOCK_SCHEMA, attributes, SECRET_SEARCH_NONE, NULL, on_complete_get_result, &result); g_hash_table_unref (attributes); g_assert_null (result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); items = secret_service_search_finish (test->service, result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_null (items->next); g_list_free_full (items, g_object_unref); } static void test_search_all_sync (Test *test, gconstpointer used) { GHashTable *attributes; GError *error = NULL; GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); items = secret_service_search_sync (test->service, &MOCK_SCHEMA, attributes, SECRET_SEARCH_ALL, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_false (secret_item_get_locked (items->data)); g_assert_null (secret_item_get_secret (items->data)); g_assert_nonnull (items->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_true (secret_item_get_locked (items->next->data)); g_assert_null (secret_item_get_secret (items->next->data)); g_assert_null (items->next->next); g_list_free_full (items, g_object_unref); } static void test_search_all_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GHashTable *attributes; GError *error = NULL; GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); secret_service_search (test->service, &MOCK_SCHEMA, attributes, SECRET_SEARCH_ALL, NULL, on_complete_get_result, &result); g_hash_table_unref (attributes); g_assert_null (result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); items = secret_service_search_finish (test->service, result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_false (secret_item_get_locked (items->data)); g_assert_null (secret_item_get_secret (items->data)); g_assert_nonnull (items->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_true (secret_item_get_locked (items->next->data)); g_assert_null (secret_item_get_secret (items->next->data)); g_assert_null (items->next->next); g_list_free_full (items, g_object_unref); } static void test_search_unlock_sync (Test *test, gconstpointer used) { GHashTable *attributes; GError *error = NULL; GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); items = secret_service_search_sync (test->service, &MOCK_SCHEMA, attributes, SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_false (secret_item_get_locked (items->data)); g_assert_null (secret_item_get_secret (items->data)); g_assert_nonnull (items->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_false (secret_item_get_locked (items->next->data)); g_assert_null (secret_item_get_secret (items->next->data)); g_assert_null (items->next->next); g_list_free_full (items, g_object_unref); } static void test_search_unlock_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GHashTable *attributes; GError *error = NULL; GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); secret_service_search (test->service, &MOCK_SCHEMA, attributes, SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK, NULL, on_complete_get_result, &result); g_hash_table_unref (attributes); g_assert_null (result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); items = secret_service_search_finish (test->service, result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_false (secret_item_get_locked (items->data)); g_assert_null (secret_item_get_secret (items->data)); g_assert_nonnull (items->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_false (secret_item_get_locked (items->next->data)); g_assert_null (secret_item_get_secret (items->next->data)); g_assert_null (items->next->next); g_list_free_full (items, g_object_unref); } static void test_search_secrets_sync (Test *test, gconstpointer used) { GHashTable *attributes; GError *error = NULL; SecretValue *value; GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); items = secret_service_search_sync (test->service, &MOCK_SCHEMA, attributes, SECRET_SEARCH_ALL | SECRET_SEARCH_LOAD_SECRETS, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_false (secret_item_get_locked (items->data)); value = secret_item_get_secret (items->data); g_assert_nonnull (value); secret_value_unref (value); g_assert_nonnull (items->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_true (secret_item_get_locked (items->next->data)); g_assert_null (secret_item_get_secret (items->next->data)); g_assert_null (items->next->next); g_list_free_full (items, g_object_unref); } static void test_search_secrets_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GHashTable *attributes; GError *error = NULL; SecretValue *value; GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); secret_service_search (test->service, &MOCK_SCHEMA, attributes, SECRET_SEARCH_ALL | SECRET_SEARCH_LOAD_SECRETS, NULL, on_complete_get_result, &result); g_hash_table_unref (attributes); g_assert_null (result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); items = secret_service_search_finish (test->service, result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_nonnull (items); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); g_assert_false (secret_item_get_locked (items->data)); value = secret_item_get_secret (items->data); g_assert_nonnull (value); secret_value_unref (value); g_assert_nonnull (items->next); g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_true (secret_item_get_locked (items->next->data)); g_assert_null (secret_item_get_secret (items->next->data)); g_assert_null (items->next->next); g_list_free_full (items, g_object_unref); } static void test_lock_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/lockone"; SecretCollection *collection; GError *error = NULL; GList *locked; GList *objects; gboolean ret; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); objects = g_list_append (NULL, collection); ret = secret_service_lock_sync (test->service, objects, NULL, &locked, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (locked); g_assert_true (locked->data == collection); g_assert_null (locked->next); g_list_free_full (locked, g_object_unref); g_list_free (objects); g_object_unref (collection); } static void test_unlock_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/lockone"; SecretCollection *collection; GError *error = NULL; GList *unlocked; GList *objects; gboolean ret; collection = secret_collection_new_for_dbus_path_sync (test->service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); objects = g_list_append (NULL, collection); ret = secret_service_unlock_sync (test->service, objects, NULL, &unlocked, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (unlocked); g_assert_true (unlocked->data == collection); g_assert_null (unlocked->next); g_list_free_full (unlocked, g_object_unref); g_list_free (objects); g_object_unref (collection); } static void test_clear_sync (Test *test, gconstpointer used) { GError *error = NULL; GHashTable *attributes; gboolean ret; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "one", "number", 1, NULL); ret = secret_service_clear_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_hash_table_unref (attributes); } static void test_clear_async (Test *test, gconstpointer used) { GError *error = NULL; GAsyncResult *result = NULL; GHashTable *attributes; gboolean ret; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "one", "number", 1, NULL); secret_service_clear (test->service, &MOCK_SCHEMA, attributes, NULL, on_complete_get_result, &result); g_hash_table_unref (attributes); g_assert_null (result); egg_test_wait (); ret = secret_service_clear_finish (test->service, result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); } static void test_clear_locked (Test *test, gconstpointer used) { GError *error = NULL; GHashTable *attributes; gboolean ret; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "tres", "number", 3, NULL); /* Locked items can't be removed via this API */ ret = secret_service_clear_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &error); g_hash_table_unref (attributes); g_assert_no_error (error); g_assert_false (ret); } static void test_clear_no_match (Test *test, gconstpointer used) { GError *error = NULL; GHashTable *attributes; gboolean ret; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", TRUE, "string", "one", NULL); /* Won't match anything */ ret = secret_service_clear_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &error); g_hash_table_unref (attributes); g_assert_no_error (error); g_assert_false (ret); } static void test_clear_no_name (Test *test, gconstpointer used) { const gchar *paths[] = { "/org/freedesktop/secrets/collection/german", NULL }; GError *error = NULL; GHashTable *attributes; gboolean ret; attributes = secret_attributes_build (&MOCK_SCHEMA, "number", 5, NULL); /* Shouldn't match anything, because no item with 5 in mock schema */ ret = secret_service_clear_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &error); g_assert_no_error (error); g_assert_false (ret); /* We need this collection unlocked for the next test */ secret_service_unlock_dbus_paths_sync (test->service, paths, NULL, NULL, &error); g_assert_no_error (error); /* We have an item with 5 in prime schema, but should match anyway becase of flags */ ret = secret_service_clear_sync (test->service, &NO_NAME_SCHEMA, attributes, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_hash_table_unref (attributes); } static void test_lookup_sync (Test *test, gconstpointer used) { GError *error = NULL; GHashTable *attributes; SecretValue *value; gsize length; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "one", "number", 1, NULL); value = secret_service_lookup_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); g_assert_nonnull (value); g_assert_cmpstr (secret_value_get (value, &length), ==, "111"); g_assert_cmpuint (length, ==, 3); secret_value_unref (value); } static void test_lookup_async (Test *test, gconstpointer used) { GError *error = NULL; GHashTable *attributes; GAsyncResult *result = NULL; SecretValue *value; gsize length; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "one", "number", 1, NULL); secret_service_lookup (test->service, &MOCK_SCHEMA, attributes, NULL, on_complete_get_result, &result); g_assert_null (result); g_hash_table_unref (attributes); egg_test_wait (); value = secret_service_lookup_finish (test->service, result, &error); g_assert_no_error (error); g_assert_nonnull (value); g_assert_cmpstr (secret_value_get (value, &length), ==, "111"); g_assert_cmpuint (length, ==, 3); secret_value_unref (value); g_object_unref (result); } static void test_lookup_locked (Test *test, gconstpointer used) { GError *error = NULL; GHashTable *attributes; SecretValue *value; gsize length; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "tres", "number", 3, NULL); value = secret_service_lookup_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &error); g_assert_no_error (error); g_hash_table_unref (attributes); g_assert_nonnull (value); g_assert_cmpstr (secret_value_get (value, &length), ==, "3333"); g_assert_cmpuint (length, ==, 4); secret_value_unref (value); } static void test_lookup_no_match (Test *test, gconstpointer used) { GError *error = NULL; GHashTable *attributes; SecretValue *value; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", TRUE, "string", "one", NULL); /* Won't match anything */ value = secret_service_lookup_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &error); g_assert_no_error (error); g_assert_null (value); g_hash_table_unref (attributes); } static void test_lookup_no_name (Test *test, gconstpointer used) { GError *error = NULL; GHashTable *attributes; SecretValue *value; gsize length; attributes = secret_attributes_build (&MOCK_SCHEMA, "number", 5, NULL); /* should return null, because nothing with mock schema and 5 */ value = secret_service_lookup_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &error); g_assert_no_error (error); g_assert_null (value); /* should return an item, because we have a prime schema with 5, and flags not to match name */ value = secret_service_lookup_sync (test->service, &NO_NAME_SCHEMA, attributes, NULL, &error); g_assert_no_error (error); g_assert_nonnull (value); g_assert_cmpstr (secret_value_get (value, &length), ==, "555"); g_assert_cmpuint (length, ==, 3); secret_value_unref (value); g_hash_table_unref (attributes); } static void test_store_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretValue *value = secret_value_new ("apassword", -1, "text/plain"); GHashTable *attributes; GError *error = NULL; gchar **paths; gboolean ret; gsize length; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "seventeen", "number", 17, NULL); ret = secret_service_store_sync (test->service, &MOCK_SCHEMA, attributes, collection_path, "New Item Label", value, NULL, &error); g_assert_true (ret); g_assert_no_error (error); secret_value_unref (value); g_hash_table_unref (attributes); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "even", "false"); g_hash_table_insert (attributes, "string", "seventeen"); g_hash_table_insert (attributes, "number", "17"); ret = secret_service_search_for_dbus_paths_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &paths, NULL, &error); g_hash_table_unref (attributes); g_assert_true (ret); g_assert_nonnull (paths); g_assert_nonnull (paths[0]); g_assert_null (paths[1]); value = secret_service_get_secret_for_dbus_path_sync (test->service, paths[0], NULL, &error); g_assert_no_error (error); g_assert_nonnull (value); g_assert_cmpstr (secret_value_get (value, &length), ==, "apassword"); g_assert_cmpuint (length, ==, 9); secret_value_unref (value); g_strfreev (paths); } static void test_store_replace (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretValue *value = secret_value_new ("apassword", -1, "text/plain"); GHashTable *attributes; GError *error = NULL; gchar **paths; gboolean ret; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "seventeen", "number", 17, NULL); ret = secret_service_store_sync (test->service, &MOCK_SCHEMA, attributes, collection_path, "New Item Label", value, NULL, &error); g_assert_true (ret); g_assert_no_error (error); ret = secret_service_store_sync (test->service, &MOCK_SCHEMA, attributes, collection_path, "Another Label", value, NULL, &error); g_assert_true (ret); g_assert_no_error (error); secret_value_unref (value); g_hash_table_unref (attributes); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "even", "false"); g_hash_table_insert (attributes, "string", "seventeen"); g_hash_table_insert (attributes, "number", "17"); ret = secret_service_search_for_dbus_paths_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &paths, NULL, &error); g_hash_table_unref (attributes); g_assert_true (ret); g_assert_nonnull (paths); g_assert_nonnull (paths[0]); g_assert_null (paths[1]); g_strfreev (paths); } static void test_store_async (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; SecretValue *value = secret_value_new ("apassword", -1, "text/plain"); GAsyncResult *result = NULL; GHashTable *attributes; GError *error = NULL; gchar **paths; gboolean ret; gsize length; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "seventeen", "number", 17, NULL); secret_service_store (test->service, &MOCK_SCHEMA, attributes, collection_path, "New Item Label", value, NULL, on_complete_get_result, &result); g_assert_null (result); secret_value_unref (value); g_hash_table_unref (attributes); egg_test_wait (); ret = secret_service_store_finish (test->service, result, &error); g_assert_true (ret); g_assert_no_error (error); g_object_unref (result); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "even", "false"); g_hash_table_insert (attributes, "string", "seventeen"); g_hash_table_insert (attributes, "number", "17"); ret = secret_service_search_for_dbus_paths_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &paths, NULL, &error); g_hash_table_unref (attributes); g_assert_true (ret); g_assert_nonnull (paths); g_assert_nonnull (paths[0]); g_assert_null (paths[1]); value = secret_service_get_secret_for_dbus_path_sync (test->service, paths[0], NULL, &error); g_assert_no_error (error); g_assert_nonnull (value); g_assert_cmpstr (secret_value_get (value, &length), ==, "apassword"); g_assert_cmpuint (length, ==, 9); secret_value_unref (value); g_strfreev (paths); } static void test_store_no_default (Test *test, gconstpointer used) { SecretValue *value = secret_value_new ("apassword", -1, "text/plain"); GHashTable *attributes; GError *error = NULL; gchar **paths; gboolean ret; gsize length; attributes = secret_attributes_build (&MOCK_SCHEMA, "even", FALSE, "string", "seventeen", "number", 17, NULL); ret = secret_service_store_sync (test->service, &MOCK_SCHEMA, attributes, SECRET_COLLECTION_DEFAULT, "New Item Label", value, NULL, &error); g_assert_true (ret); g_assert_no_error (error); secret_value_unref (value); g_hash_table_unref (attributes); attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "even", "false"); g_hash_table_insert (attributes, "string", "seventeen"); g_hash_table_insert (attributes, "number", "17"); ret = secret_service_search_for_dbus_paths_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &paths, NULL, &error); g_hash_table_unref (attributes); g_assert_true (ret); g_assert_nonnull (paths); g_assert_nonnull (paths[0]); g_assert_null (paths[1]); value = secret_service_get_secret_for_dbus_path_sync (test->service, paths[0], NULL, &error); g_assert_no_error (error); g_assert_nonnull (value); g_assert_cmpstr (secret_value_get (value, &length), ==, "apassword"); g_assert_cmpuint (length, ==, 9); secret_value_unref (value); g_strfreev (paths); } static void test_set_alias_sync (Test *test, gconstpointer used) { SecretCollection *collection; gchar *blah; GError *error = NULL; gboolean ret; blah = secret_service_read_alias_dbus_path_sync (test->service, "blah", NULL, &error); g_assert_no_error (error); g_assert_null (blah); collection = secret_collection_new_for_dbus_path_sync (test->service, "/org/freedesktop/secrets/collection/english", SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); g_assert_true (SECRET_IS_COLLECTION (collection)); ret = secret_service_set_alias_sync (test->service, "blah", collection, NULL, &error); g_assert_no_error (error); g_assert_true (ret); blah = secret_service_read_alias_dbus_path_sync (test->service, "blah", NULL, &error); g_assert_no_error (error); g_assert_cmpstr (blah, ==, g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection))); g_free (blah); ret = secret_service_set_alias_sync (test->service, "blah", NULL, NULL, &error); g_assert_no_error (error); g_assert_true (ret); blah = secret_service_read_alias_dbus_path_sync (test->service, "blah", NULL, &error); g_assert_no_error (error); g_assert_null (blah); g_object_unref (collection); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-service"); g_test_add ("/service/search-sync", Test, "mock-service-normal.py", setup, test_search_sync, teardown); g_test_add ("/service/search-async", Test, "mock-service-normal.py", setup, test_search_async, teardown); g_test_add ("/service/search-all-sync", Test, "mock-service-normal.py", setup, test_search_all_sync, teardown); g_test_add ("/service/search-all-async", Test, "mock-service-normal.py", setup, test_search_all_async, teardown); g_test_add ("/service/search-unlock-sync", Test, "mock-service-normal.py", setup, test_search_unlock_sync, teardown); g_test_add ("/service/search-unlock-async", Test, "mock-service-normal.py", setup, test_search_unlock_async, teardown); g_test_add ("/service/search-secrets-sync", Test, "mock-service-normal.py", setup, test_search_secrets_sync, teardown); g_test_add ("/service/search-secrets-async", Test, "mock-service-normal.py", setup, test_search_secrets_async, teardown); g_test_add ("/service/lock-sync", Test, "mock-service-lock.py", setup, test_lock_sync, teardown); g_test_add ("/service/unlock-sync", Test, "mock-service-lock.py", setup, test_unlock_sync, teardown); g_test_add ("/service/lookup-sync", Test, "mock-service-normal.py", setup, test_lookup_sync, teardown); g_test_add ("/service/lookup-async", Test, "mock-service-normal.py", setup, test_lookup_async, teardown); g_test_add ("/service/lookup-locked", Test, "mock-service-normal.py", setup, test_lookup_locked, teardown); g_test_add ("/service/lookup-no-match", Test, "mock-service-normal.py", setup, test_lookup_no_match, teardown); g_test_add ("/service/lookup-no-name", Test, "mock-service-normal.py", setup, test_lookup_no_name, teardown); g_test_add ("/service/clear-sync", Test, "mock-service-delete.py", setup, test_clear_sync, teardown); g_test_add ("/service/clear-async", Test, "mock-service-delete.py", setup, test_clear_async, teardown); g_test_add ("/service/clear-locked", Test, "mock-service-delete.py", setup, test_clear_locked, teardown); g_test_add ("/service/clear-no-match", Test, "mock-service-delete.py", setup, test_clear_no_match, teardown); g_test_add ("/service/clear-no-name", Test, "mock-service-delete.py", setup, test_clear_no_name, teardown); g_test_add ("/service/store-sync", Test, "mock-service-normal.py", setup, test_store_sync, teardown); g_test_add ("/service/store-async", Test, "mock-service-normal.py", setup, test_store_async, teardown); g_test_add ("/service/store-replace", Test, "mock-service-normal.py", setup, test_store_replace, teardown); g_test_add ("/service/store-no-default", Test, "mock-service-empty.py", setup, test_store_no_default, teardown); g_test_add ("/service/set-alias-sync", Test, "mock-service-normal.py", setup, test_set_alias_sync, teardown); return egg_tests_run_with_loop (); } 07070100000088000081A400000000000000000000000167D9F0D900003FBB000000000000000000000000000000000000002B00000000libsecret-0.21.7/libsecret/test-password.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-password.h" #include "secret-paths.h" #include "secret-private.h" #include "mock-service.h" #include "egg/egg-testing.h" #include #include #include static const SecretSchema MOCK_SCHEMA = { "org.mock.Schema", SECRET_SCHEMA_NONE, { { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, } }; static const SecretSchema NO_NAME_SCHEMA = { "unused.Schema.Name", SECRET_SCHEMA_DONT_MATCH_NAME, { { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, } }; typedef struct { GPid pid; } Test; static void setup (Test *test, gconstpointer data) { GError *error = NULL; const gchar *mock_script = data; mock_service_start (mock_script, &error); g_assert_no_error (error); } static void teardown (Test *test, gconstpointer unused) { secret_service_disconnect (); mock_service_stop (); } static void on_complete_get_result (GObject *source, GAsyncResult *result, gpointer user_data) { GAsyncResult **ret = user_data; g_assert_nonnull (ret); g_assert_null (*ret); *ret = g_object_ref (result); egg_test_wait_stop (); } static void test_lookup_sync (Test *test, gconstpointer used) { gchar *password; GError *error = NULL; password = secret_password_lookup_nonpageable_sync (&MOCK_SCHEMA, NULL, &error, "even", FALSE, "string", "one", "number", 1, NULL); g_assert_no_error (error); g_assert_cmpstr (password, ==, "111"); secret_password_free (password); } static void test_lookup_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GError *error = NULL; gchar *password; secret_password_lookup (&MOCK_SCHEMA, NULL, on_complete_get_result, &result, "even", FALSE, "string", "one", "number", 1, NULL); g_assert_null (result); egg_test_wait (); password = secret_password_lookup_nonpageable_finish (result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_cmpstr (password, ==, "111"); secret_password_free (password); } static void test_lookup_no_name (Test *test, gconstpointer used) { GError *error = NULL; gchar *password; /* should return null, because nothing with mock schema and 5 */ password = secret_password_lookup_sync (&MOCK_SCHEMA, NULL, &error, "number", 5, NULL); g_assert_no_error (error); g_assert_null (password); /* should return an item, because we have a prime schema with 5, and flags not to match name */ password = secret_password_lookup_sync (&NO_NAME_SCHEMA, NULL, &error, "number", 5, NULL); g_assert_no_error (error); g_assert_cmpstr (password, ==, "555"); secret_password_free (password); } static void test_store_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GError *error = NULL; gchar *password; gboolean ret; ret = secret_password_store_sync (&MOCK_SCHEMA, collection_path, "Label here", "the password", NULL, &error, "even", TRUE, "string", "twelve", "number", 12, NULL); g_assert_no_error (error); g_assert_true (ret); password = secret_password_lookup_nonpageable_sync (&MOCK_SCHEMA, NULL, &error, "string", "twelve", NULL); g_assert_no_error (error); g_assert_cmpstr (password, ==, "the password"); secret_password_free (password); } static void test_store_async (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GAsyncResult *result = NULL; GError *error = NULL; gchar *password; gboolean ret; secret_password_store (&MOCK_SCHEMA, collection_path, "Label here", "the password", NULL, on_complete_get_result, &result, "even", TRUE, "string", "twelve", "number", 12, NULL); g_assert_null (result); egg_test_wait (); ret = secret_password_store_finish (result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); password = secret_password_lookup_nonpageable_sync (&MOCK_SCHEMA, NULL, &error, "string", "twelve", NULL); g_assert_no_error (error); g_assert_cmpstr (password, ==, "the password"); secret_password_free (password); } static void test_store_unlock (Test *test, gconstpointer unused) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GAsyncResult *result = NULL; SecretCollection *collection; SecretService *service; GError *error = NULL; gchar *password; gboolean ret; GList *objects; gint count; service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); /* Check collection state */ collection = secret_collection_new_for_dbus_path_sync (service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_assert_no_error (error); g_assert_false (secret_collection_get_locked (collection)); /* Lock it, use async, so collection properties update */ objects = g_list_append (NULL, collection); secret_service_lock (service, objects, NULL, on_complete_get_result, &result); egg_test_wait (); count = secret_service_lock_finish (service, result, NULL, &error); g_assert_cmpint (count, ==, 1); g_clear_object (&result); g_list_free (objects); /* Check collection state */ g_assert_true (secret_collection_get_locked (collection)); /* Store the password, use async so collection properties update */ secret_password_store (&MOCK_SCHEMA, collection_path, "Label here", "the password", NULL, on_complete_get_result, &result, "even", TRUE, "string", "twelve", "number", 12, NULL); g_assert_null (result); egg_test_wait (); ret = secret_password_store_finish (result, &error); g_assert_no_error (error); g_assert_true (ret); g_clear_object (&result); /* Check collection state */ g_assert_false (secret_collection_get_locked (collection)); password = secret_password_lookup_nonpageable_sync (&MOCK_SCHEMA, NULL, &error, "string", "twelve", NULL); g_assert_no_error (error); g_assert_cmpstr (password, ==, "the password"); secret_password_free (password); g_object_unref (collection); g_object_unref (service); } static void test_delete_sync (Test *test, gconstpointer used) { GError *error = NULL; gboolean ret; ret = secret_password_clear_sync (&MOCK_SCHEMA, NULL, &error, "even", FALSE, "string", "one", "number", 1, NULL); g_assert_no_error (error); g_assert_true (ret); } static void test_delete_async (Test *test, gconstpointer used) { GError *error = NULL; GAsyncResult *result = NULL; gboolean ret; secret_password_clear (&MOCK_SCHEMA, NULL, on_complete_get_result, &result, "even", FALSE, "string", "one", "number", 1, NULL); g_assert_null (result); egg_test_wait (); ret = secret_password_clear_finish (result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); } static void test_clear_no_name (Test *test, gconstpointer used) { const gchar *paths[] = { "/org/freedesktop/secrets/collection/german", NULL }; SecretService *service; GError *error = NULL; gboolean ret; /* Shouldn't match anything, because no item with 5 in mock schema */ ret = secret_password_clear_sync (&MOCK_SCHEMA, NULL, &error, "number", 5, NULL); g_assert_no_error (error); g_assert_false (ret); /* We need this collection unlocked for the next test */ service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); secret_service_unlock_dbus_paths_sync (service, paths, NULL, NULL, &error); g_assert_no_error (error); g_object_unref (service); /* We have an item with 5 in prime schema, but should match anyway becase of flags */ ret = secret_password_clear_sync (&NO_NAME_SCHEMA, NULL, &error, "number", 5, NULL); g_assert_no_error (error); g_assert_true (ret); } static void free_attributes (gpointer data, gpointer user_data) { g_object_unref ((GObject *)data); } static void test_search_sync (Test *test, gconstpointer used) { GList *items; GError *error = NULL; items = secret_password_search_sync (&MOCK_SCHEMA, SECRET_SEARCH_ALL, NULL, &error, "even", FALSE, "string", "one", "number", 1, NULL); g_assert_no_error (error); g_assert_cmpint (g_list_length (items), ==, 1); g_list_foreach (items, free_attributes, NULL); g_list_free (items); } static void test_search_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GError *error = NULL; GList *items; secret_password_search (&MOCK_SCHEMA, SECRET_SEARCH_ALL, NULL, on_complete_get_result, &result, "even", FALSE, "string", "one", "number", 1, NULL); g_assert (result == NULL); egg_test_wait (); items = secret_password_search_finish (result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_cmpint (g_list_length (items), ==, 1); g_list_foreach (items, free_attributes, NULL); g_list_free (items); } static void test_search_no_name (Test *test, gconstpointer used) { GError *error = NULL; GList *items; /* should return null, because nothing with mock schema and 5 */ items = secret_password_search_sync (&MOCK_SCHEMA, SECRET_SEARCH_ALL, NULL, &error, "number", 5, NULL); g_assert_no_error (error); g_assert (items == NULL); /* should return an item, because we have a prime schema with 5, and flags not to match name */ items = secret_password_search_sync (&NO_NAME_SCHEMA, SECRET_SEARCH_ALL, NULL, &error, "number", 5, NULL); g_assert_no_error (error); g_assert_cmpint (g_list_length (items), ==, 1); g_list_foreach (items, free_attributes, NULL); g_list_free (items); } static void test_binary_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GError *error = NULL; SecretValue *value; gboolean ret; value = secret_value_new ("the password", -1, "text/plain"); ret = secret_password_store_binary_sync (&MOCK_SCHEMA, collection_path, "Label here", value, NULL, &error, "even", TRUE, "string", "twelve", "number", 12, NULL); g_assert_no_error (error); g_assert_true (ret); secret_value_unref (value); value = secret_password_lookup_binary_sync (&MOCK_SCHEMA, NULL, &error, "string", "twelve", NULL); g_assert_no_error (error); g_assert_cmpstr (secret_value_get_text (value), ==, "the password"); secret_value_unref (value); } static void test_binary_async (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GAsyncResult *result = NULL; GError *error = NULL; SecretValue *value; gboolean ret; value = secret_value_new ("the password", -1, "text/plain"); secret_password_store_binary (&MOCK_SCHEMA, collection_path, "Label here", value, NULL, on_complete_get_result, &result, "even", TRUE, "string", "twelve", "number", 12, NULL); g_assert_null (result); secret_value_unref (value); egg_test_wait (); ret = secret_password_store_finish (result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); value = secret_password_lookup_binary_sync (&MOCK_SCHEMA, NULL, &error, "string", "twelve", NULL); g_assert_no_error (error); g_assert_nonnull (value); g_assert_cmpstr (secret_value_get_text (value), ==, "the password"); secret_value_unref (value); } static void test_password_free_null (void) { secret_password_free (NULL); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-password"); g_test_add ("/password/lookup-sync", Test, "mock-service-normal.py", setup, test_lookup_sync, teardown); g_test_add ("/password/lookup-async", Test, "mock-service-normal.py", setup, test_lookup_async, teardown); g_test_add ("/password/lookup-no-name", Test, "mock-service-normal.py", setup, test_lookup_no_name, teardown); g_test_add ("/password/store-sync", Test, "mock-service-normal.py", setup, test_store_sync, teardown); g_test_add ("/password/store-async", Test, "mock-service-normal.py", setup, test_store_async, teardown); g_test_add ("/password/store-unlock", Test, "mock-service-normal.py", setup, test_store_unlock, teardown); g_test_add ("/password/delete-sync", Test, "mock-service-delete.py", setup, test_delete_sync, teardown); g_test_add ("/password/delete-async", Test, "mock-service-delete.py", setup, test_delete_async, teardown); g_test_add ("/password/clear-no-name", Test, "mock-service-delete.py", setup, test_clear_no_name, teardown); g_test_add ("/password/search-sync", Test, "mock-service-normal.py", setup, test_search_sync, teardown); g_test_add ("/password/search-async", Test, "mock-service-normal.py", setup, test_search_async, teardown); g_test_add ("/password/search-no-name", Test, "mock-service-normal.py", setup, test_search_no_name, teardown); g_test_add ("/password/binary-sync", Test, "mock-service-normal.py", setup, test_binary_sync, teardown); g_test_add ("/password/binary-async", Test, "mock-service-normal.py", setup, test_binary_async, teardown); g_test_add_func ("/password/free-null", test_password_free_null); return egg_tests_run_with_loop (); } 07070100000089000081A400000000000000000000000167D9F0D900005C8E000000000000000000000000000000000000002800000000libsecret-0.21.7/libsecret/test-paths.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-attributes.h" #include "secret-collection.h" #include "secret-item.h" #include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "mock-service.h" #include "egg/egg-testing.h" #include #include #include static const SecretSchema MOCK_SCHEMA = { "org.mock.Schema", SECRET_SCHEMA_NONE, { { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, } }; typedef struct { SecretService *service; } Test; static void setup_mock (Test *test, gconstpointer data) { GError *error = NULL; const gchar *mock_script = data; mock_service_start (mock_script, &error); g_assert_no_error (error); } static void setup (Test *test, gconstpointer data) { GError *error = NULL; setup_mock (test, data); test->service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (test->service), (gpointer *)&test->service); } static void teardown_mock (Test *test, gconstpointer unused) { secret_service_disconnect (); mock_service_stop (); } static void teardown (Test *test, gconstpointer unused) { egg_test_wait_idle (); g_object_unref (test->service); secret_service_disconnect (); g_assert_null (test->service); teardown_mock (test, unused); } static void on_complete_get_result (GObject *source, GAsyncResult *result, gpointer user_data) { GAsyncResult **ret = user_data; g_assert_nonnull (ret); g_assert_null (*ret); *ret = g_object_ref (result); egg_test_wait_stop (); } static void test_search_paths_sync (Test *test, gconstpointer used) { GHashTable *attributes; gboolean ret; gchar **locked; gchar **unlocked; GError *error = NULL; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); ret = secret_service_search_for_dbus_paths_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &unlocked, &locked, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (locked); g_assert_cmpstr (locked[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_nonnull (unlocked); g_assert_cmpstr (unlocked[0], ==, "/org/freedesktop/secrets/collection/english/1"); g_strfreev (unlocked); g_strfreev (locked); g_hash_table_unref (attributes); } static void test_search_paths_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GHashTable *attributes; gboolean ret; gchar **locked; gchar **unlocked; GError *error = NULL; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); secret_service_search_for_dbus_paths (test->service, &MOCK_SCHEMA, attributes, NULL, on_complete_get_result, &result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); ret = secret_service_search_for_dbus_paths_finish (test->service, result, &unlocked, &locked, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (locked); g_assert_cmpstr (locked[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); g_assert_nonnull (unlocked); g_assert_cmpstr (unlocked[0], ==, "/org/freedesktop/secrets/collection/english/1"); g_strfreev (unlocked); g_strfreev (locked); g_object_unref (result); g_hash_table_unref (attributes); } static void test_search_paths_nulls (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GHashTable *attributes; gboolean ret; gchar **paths; GError *error = NULL; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); ret = secret_service_search_for_dbus_paths_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &paths, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (paths); g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/english/1"); g_strfreev (paths); ret = secret_service_search_for_dbus_paths_sync (test->service, &MOCK_SCHEMA, attributes, NULL, NULL, &paths, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (paths); g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); g_strfreev (paths); ret = secret_service_search_for_dbus_paths_sync (test->service, &MOCK_SCHEMA, attributes, NULL, NULL, NULL, &error); g_assert_no_error (error); g_assert_true (ret); secret_service_search_for_dbus_paths (test->service, &MOCK_SCHEMA, attributes, NULL, on_complete_get_result, &result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); ret = secret_service_search_for_dbus_paths_finish (test->service, result, &paths, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (paths); g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/english/1"); g_strfreev (paths); g_clear_object (&result); secret_service_search_for_dbus_paths (test->service, &MOCK_SCHEMA, attributes, NULL, on_complete_get_result, &result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); ret = secret_service_search_for_dbus_paths_finish (test->service, result, NULL, &paths, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (paths); g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); g_strfreev (paths); g_clear_object (&result); secret_service_search_for_dbus_paths (test->service, &MOCK_SCHEMA, attributes, NULL, on_complete_get_result, &result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); ret = secret_service_search_for_dbus_paths_finish (test->service, result, NULL, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_clear_object (&result); g_hash_table_unref (attributes); } static void test_secret_for_path_sync (Test *test, gconstpointer used) { SecretValue *value; GError *error = NULL; const gchar *path; const gchar *password; gsize length; path = "/org/freedesktop/secrets/collection/english/1"; value = secret_service_get_secret_for_dbus_path_sync (test->service, path, NULL, &error); g_assert_no_error (error); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "111"); password = secret_value_get (value, NULL); g_assert_cmpstr (password, ==, "111"); secret_value_unref (value); } static void test_secret_for_path_async (Test *test, gconstpointer used) { SecretValue *value; GError *error = NULL; const gchar *path; const gchar *password; GAsyncResult *result = NULL; gsize length; path = "/org/freedesktop/secrets/collection/english/1"; secret_service_get_secret_for_dbus_path (test->service, path, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); value = secret_service_get_secret_for_dbus_path_finish (test->service, result, &error); g_assert_no_error (error); g_assert_nonnull (value); g_object_unref (result); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "111"); password = secret_value_get (value, NULL); g_assert_cmpstr (password, ==, "111"); secret_value_unref (value); } static void test_secrets_for_paths_sync (Test *test, gconstpointer used) { const gchar *path_item_one = "/org/freedesktop/secrets/collection/english/1"; const gchar *path_item_two = "/org/freedesktop/secrets/collection/english/2"; const gchar *paths[] = { path_item_one, path_item_two, /* This one is locked, and not returned */ "/org/freedesktop/secrets/collection/spanish/10", NULL }; SecretValue *value; GHashTable *values; GError *error = NULL; const gchar *password; gsize length; values = secret_service_get_secrets_for_dbus_paths_sync (test->service, paths, NULL, &error); g_assert_no_error (error); g_assert_nonnull (values); g_assert_cmpuint (g_hash_table_size (values), ==, 2); value = g_hash_table_lookup (values, path_item_one); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "111"); value = g_hash_table_lookup (values, path_item_two); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "222"); g_hash_table_unref (values); } static void test_secrets_for_paths_async (Test *test, gconstpointer used) { const gchar *path_item_one = "/org/freedesktop/secrets/collection/english/1"; const gchar *path_item_two = "/org/freedesktop/secrets/collection/english/2"; const gchar *paths[] = { path_item_one, path_item_two, /* This one is locked, and not returned */ "/org/freedesktop/secrets/collection/spanish/10", NULL }; SecretValue *value; GHashTable *values; GError *error = NULL; const gchar *password; GAsyncResult *result = NULL; gsize length; secret_service_get_secrets_for_dbus_paths (test->service, paths, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); values = secret_service_get_secrets_for_dbus_paths_finish (test->service, result, &error); g_assert_no_error (error); g_object_unref (result); g_assert_nonnull (values); g_assert_cmpuint (g_hash_table_size (values), ==, 2); value = g_hash_table_lookup (values, path_item_one); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "111"); value = g_hash_table_lookup (values, path_item_two); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 3); g_assert_cmpstr (password, ==, "222"); g_hash_table_unref (values); } static void test_delete_for_path_sync (Test *test, gconstpointer used) { const gchar *path_item_one = "/org/freedesktop/secrets/collection/todelete/item"; GError *error = NULL; gboolean ret; ret = secret_service_delete_item_dbus_path_sync (test->service, path_item_one, NULL, &error); g_assert_no_error (error); g_assert_true (ret); } static void test_delete_for_path_sync_prompt (Test *test, gconstpointer used) { const gchar *path_item_one = "/org/freedesktop/secrets/collection/todelete/confirm"; GError *error = NULL; gboolean ret; ret = secret_service_delete_item_dbus_path_sync (test->service, path_item_one, NULL, &error); g_assert_no_error (error); g_assert_true (ret); } static void test_lock_paths_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/lockone"; const gchar *paths[] = { collection_path, NULL, }; GError *error = NULL; gchar **locked = NULL; gboolean ret; ret = secret_service_lock_dbus_paths_sync (test->service, paths, NULL, &locked, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (locked); g_assert_cmpstr (locked[0], ==, collection_path); g_assert_null (locked[1]); g_strfreev (locked); } static void test_lock_prompt_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/lockprompt"; const gchar *paths[] = { collection_path, NULL, }; GError *error = NULL; gchar **locked = NULL; gboolean ret; ret = secret_service_lock_dbus_paths_sync (test->service, paths, NULL, &locked, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (locked); g_assert_cmpstr (locked[0], ==, collection_path); g_assert_null (locked[1]); g_strfreev (locked); } static void test_unlock_paths_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/lockone"; const gchar *paths[] = { collection_path, NULL, }; GError *error = NULL; gchar **unlocked = NULL; gboolean ret; ret = secret_service_unlock_dbus_paths_sync (test->service, paths, NULL, &unlocked, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (unlocked); g_assert_cmpstr (unlocked[0], ==, collection_path); g_assert_null (unlocked[1]); g_strfreev (unlocked); } static void test_unlock_prompt_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/lockprompt"; const gchar *paths[] = { collection_path, NULL, }; GError *error = NULL; gchar **unlocked = NULL; gboolean ret; ret = secret_service_unlock_dbus_paths_sync (test->service, paths, NULL, &unlocked, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_nonnull (unlocked); g_assert_cmpstr (unlocked[0], ==, collection_path); g_assert_null (unlocked[1]); g_strfreev (unlocked); } static void test_collection_sync (Test *test, gconstpointer used) { GHashTable *properties; GError *error = NULL; gchar *path; properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_variant_unref); g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", g_variant_ref_sink (g_variant_new_string ("Wheeee"))); path = secret_service_create_collection_dbus_path_sync (test->service, properties, NULL, SECRET_COLLECTION_CREATE_NONE, NULL, &error); g_hash_table_unref (properties); g_assert_no_error (error); g_assert_nonnull (path); g_assert_true (g_str_has_prefix (path, "/org/freedesktop/secrets/collection/")); g_free (path); } static void test_collection_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GHashTable *properties; GError *error = NULL; gchar *path; properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_variant_unref); g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", g_variant_ref_sink (g_variant_new_string ("Wheeee"))); secret_service_create_collection_dbus_path (test->service, properties, NULL, SECRET_COLLECTION_CREATE_NONE, NULL, on_complete_get_result, &result); g_hash_table_unref (properties); g_assert_null (result); egg_test_wait (); path = secret_service_create_collection_dbus_path_finish (test->service, result, &error); g_object_unref (result); g_assert_no_error (error); g_assert_nonnull (path); g_assert_true (g_str_has_prefix (path, "/org/freedesktop/secrets/collection/")); g_free (path); } static void test_item_sync (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GHashTable *properties; GHashTable *attributes; SecretValue *value; GError *error = NULL; gchar *path; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "even", "true"); g_hash_table_insert (attributes, "string", "ten"); g_hash_table_insert (attributes, "number", "10"); properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_variant_unref); g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", g_variant_ref_sink (g_variant_new_string ("Wheeee"))); g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Attributes", g_variant_ref_sink (_secret_attributes_to_variant (attributes, "org.gnome.Test"))); g_hash_table_unref (attributes); value = secret_value_new ("andmoreandmore", -1, "text/plain"); path = secret_service_create_item_dbus_path_sync (test->service, collection_path, properties, value, SECRET_ITEM_CREATE_NONE, NULL, &error); secret_value_unref (value); g_hash_table_unref (properties); g_assert_no_error (error); g_assert_nonnull (path); g_assert_true (g_str_has_prefix (path, collection_path)); g_free (path); } static void test_item_async (Test *test, gconstpointer used) { const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; GHashTable *properties; GHashTable *attributes; SecretValue *value; GError *error = NULL; GAsyncResult *result = NULL; gchar *path; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "even", "true"); g_hash_table_insert (attributes, "string", "ten"); g_hash_table_insert (attributes, "number", "10"); properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_variant_unref); g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", g_variant_ref_sink (g_variant_new_string ("Wheeee"))); g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Attributes", g_variant_ref_sink (_secret_attributes_to_variant (attributes, NULL))); g_hash_table_unref (attributes); value = secret_value_new ("andmoreandmore", -1, "text/plain"); secret_service_create_item_dbus_path (test->service, collection_path, properties, value, SECRET_ITEM_CREATE_NONE, NULL, on_complete_get_result, &result); g_assert_null (result); secret_value_unref (value); g_hash_table_unref (properties); egg_test_wait (); path = secret_service_create_item_dbus_path_finish (test->service, result, &error); g_object_unref (result); g_assert_no_error (error); g_assert_nonnull (path); g_assert_true (g_str_has_prefix (path, collection_path)); g_free (path); } static void test_set_alias_path (Test *test, gconstpointer used) { gchar *path; GError *error = NULL; gboolean ret; path = secret_service_read_alias_dbus_path_sync (test->service, "blah", NULL, &error); g_assert_no_error (error); g_assert_null (path); ret = secret_service_set_alias_to_dbus_path_sync (test->service, "blah", "/org/freedesktop/secrets/collection/english", NULL, &error); g_assert_no_error (error); g_assert_true (ret); path = secret_service_read_alias_dbus_path_sync (test->service, "blah", NULL, &error); g_assert_no_error (error); g_assert_cmpstr (path, ==, "/org/freedesktop/secrets/collection/english"); g_free (path); ret = secret_service_set_alias_to_dbus_path_sync (test->service, "blah", NULL, NULL, &error); g_assert_no_error (error); g_assert_true (ret); path = secret_service_read_alias_dbus_path_sync (test->service, "blah", NULL, &error); g_assert_no_error (error); g_assert_null (path); } static void test_encode_decode_secret (Test *test, gconstpointer unused) { GVariant *variant; SecretValue *value; SecretValue *decoded; GError *error = NULL; value = secret_value_new ("zerogjuggs", -1, "text/plain"); secret_service_ensure_session_sync (test->service, NULL, &error); g_assert_no_error (error); variant = secret_service_encode_dbus_secret (test->service, value); g_assert_nonnull (variant); g_assert_cmpstr (g_variant_get_type_string (variant), ==, "(oayays)"); secret_value_unref (value); decoded = secret_service_decode_dbus_secret (test->service, variant); g_assert_nonnull (variant); g_variant_unref (variant); g_assert_cmpstr (secret_value_get_text (decoded), ==, "zerogjuggs"); secret_value_unref (decoded); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-service"); g_test_add ("/service/search-for-paths", Test, "mock-service-normal.py", setup, test_search_paths_sync, teardown); g_test_add ("/service/search-for-paths-async", Test, "mock-service-normal.py", setup, test_search_paths_async, teardown); g_test_add ("/service/search-for-paths-nulls", Test, "mock-service-normal.py", setup, test_search_paths_nulls, teardown); g_test_add ("/service/secret-for-path-sync", Test, "mock-service-normal.py", setup, test_secret_for_path_sync, teardown); g_test_add ("/service/secret-for-path-plain", Test, "mock-service-only-plain.py", setup, test_secret_for_path_sync, teardown); g_test_add ("/service/secret-for-path-async", Test, "mock-service-normal.py", setup, test_secret_for_path_async, teardown); g_test_add ("/service/secrets-for-paths-sync", Test, "mock-service-normal.py", setup, test_secrets_for_paths_sync, teardown); g_test_add ("/service/secrets-for-paths-async", Test, "mock-service-normal.py", setup, test_secrets_for_paths_async, teardown); g_test_add ("/service/delete-for-path", Test, "mock-service-delete.py", setup, test_delete_for_path_sync, teardown); g_test_add ("/service/delete-for-path-with-prompt", Test, "mock-service-delete.py", setup, test_delete_for_path_sync_prompt, teardown); g_test_add ("/service/lock-paths-sync", Test, "mock-service-lock.py", setup, test_lock_paths_sync, teardown); g_test_add ("/service/lock-prompt-sync", Test, "mock-service-lock.py", setup, test_lock_prompt_sync, teardown); g_test_add ("/service/unlock-paths-sync", Test, "mock-service-lock.py", setup, test_unlock_paths_sync, teardown); g_test_add ("/service/unlock-prompt-sync", Test, "mock-service-lock.py", setup, test_unlock_prompt_sync, teardown); g_test_add ("/service/create-collection-sync", Test, "mock-service-normal.py", setup, test_collection_sync, teardown); g_test_add ("/service/create-collection-async", Test, "mock-service-normal.py", setup, test_collection_async, teardown); g_test_add ("/service/create-item-sync", Test, "mock-service-normal.py", setup, test_item_sync, teardown); g_test_add ("/service/create-item-async", Test, "mock-service-normal.py", setup, test_item_async, teardown); g_test_add ("/service/set-alias-path", Test, "mock-service-normal.py", setup, test_set_alias_path, teardown); g_test_add ("/service/encode-decode-secret", Test, "mock-service-normal.py", setup, test_encode_decode_secret, teardown); return egg_tests_run_with_loop (); } 0707010000008A000081A400000000000000000000000167D9F0D900002E06000000000000000000000000000000000000002900000000libsecret-0.21.7/libsecret/test-prompt.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Red Hat Inc. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-item.h" #include "secret-service.h" #include "secret-private.h" #include "secret-prompt.h" #include "mock-service.h" #include "egg/egg-testing.h" #include #include #include typedef struct { SecretService *service; } Test; static void setup (Test *test, gconstpointer data) { GError *error = NULL; const gchar *mock_script = data; mock_service_start (mock_script, &error); g_assert_no_error (error); test->service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (test->service), (gpointer *)&test->service); } static void teardown (Test *test, gconstpointer unused) { g_object_unref (test->service); secret_service_disconnect (); g_assert_null (test->service); mock_service_stop (); } static void on_async_result (GObject *source, GAsyncResult *result, gpointer user_data) { GAsyncResult **ret = user_data; g_assert_nonnull (ret); g_assert_null (*ret); *ret = g_object_ref (result); egg_test_wait_stop (); } static gboolean on_idle_increment (gpointer user_data) { guint *value = user_data; ++(*value); return TRUE; } static void test_perform_sync (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GVariant *retval; guint value = 0; guint increment_id; /* Verify that main loop does not run during this call */ increment_id = g_idle_add (on_idle_increment, &value); prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple"); retval = secret_prompt_perform_sync (prompt, NULL, NULL, NULL, &error); g_assert_no_error (error); g_assert_nonnull (retval); g_variant_unref (retval); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); g_assert_cmpuint (value, ==, 0); g_source_remove (increment_id); g_object_unref (prompt); g_assert_null (prompt); } static void test_perform_run (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GVariant *retval; guint value = 0; guint increment_id; /* Verify that main loop does run during this call */ increment_id = g_idle_add (on_idle_increment, &value); prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple"); retval = secret_prompt_run (prompt, 0, NULL, NULL, &error); g_assert_no_error (error); g_assert_nonnull (retval); g_variant_unref (retval); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); g_assert_cmpuint (value, >, 0); g_source_remove (increment_id); /* Make sure everything completes */ egg_test_wait_idle (); g_object_unref (prompt); g_assert_null (prompt); } static void test_perform_async (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GAsyncResult *result = NULL; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple"); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); secret_prompt_perform (prompt, 0, NULL, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); retval = secret_prompt_perform_finish (prompt, result, &error); g_assert_no_error (error); g_assert_nonnull (retval); g_variant_unref (retval); g_object_unref (result); /* Make sure everything completes */ egg_test_wait_idle (); g_object_unref (prompt); g_assert_null (prompt); } static void test_perform_cancel (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GAsyncResult *result = NULL; GCancellable *cancellable; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/delay"); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); cancellable = g_cancellable_new (); secret_prompt_perform (prompt, 0, NULL, cancellable, on_async_result, &result); g_assert_null (result); g_cancellable_cancel (cancellable); g_object_unref (cancellable); egg_test_wait (); retval = secret_prompt_perform_finish (prompt, result, &error); g_assert_no_error (error); g_assert_nonnull (retval); g_variant_unref (retval); g_object_unref (result); g_object_unref (prompt); /* Due to GDBus threading races */ egg_test_wait_until (100); g_assert_null (prompt); } static void test_perform_fail (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/error"); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); retval = secret_prompt_perform_sync (prompt, NULL, NULL, NULL, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED); g_assert_null (retval); g_clear_error (&error); g_object_unref (prompt); g_assert_null (prompt); } static void test_perform_vanish (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/vanish"); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); retval = secret_prompt_perform_sync (prompt, NULL, NULL, NULL, &error); g_assert_no_error (error); g_assert_null (retval); g_object_unref (prompt); g_assert_null (prompt); } static void test_prompt_result (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/result"); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); retval = secret_prompt_perform_sync (prompt, 0, NULL, G_VARIANT_TYPE_STRING, &error); g_assert_no_error (error); g_assert_nonnull (retval); g_assert_cmpstr (g_variant_get_string (retval, NULL), ==, "Special Result"); g_variant_unref (retval); g_object_unref (prompt); g_assert_null (prompt); } static void test_prompt_window_id (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/window"); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); retval = secret_prompt_perform_sync (prompt, "555", NULL, G_VARIANT_TYPE_STRING, &error); g_assert_no_error (error); g_assert_nonnull (retval); g_assert_cmpstr (g_variant_get_string (retval, NULL), ==, "555"); g_variant_unref (retval); g_object_unref (prompt); g_assert_null (prompt); } static void test_service_sync (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple"); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); retval = secret_service_prompt_sync (test->service, prompt, NULL, NULL, &error); g_assert_no_error (error); g_assert_nonnull (retval); g_variant_unref (retval); g_object_unref (prompt); g_assert_null (prompt); } static void test_service_async (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GAsyncResult *result = NULL; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple"); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); secret_service_prompt (test->service, prompt, NULL, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); retval = secret_service_prompt_finish (test->service, result, &error); g_assert_no_error (error); g_assert_nonnull (retval); g_variant_unref (retval); g_object_unref (result); /* Make sure everything completes */ egg_test_wait_idle (); g_object_unref (prompt); g_assert_null (prompt); } static void test_service_fail (Test *test, gconstpointer unused) { SecretPrompt *prompt; GError *error = NULL; GAsyncResult *result = NULL; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/error"); g_object_add_weak_pointer (G_OBJECT (prompt), (gpointer *)&prompt); secret_service_prompt (test->service, prompt, NULL, NULL, on_async_result, &result); g_assert_null (result); egg_test_wait (); retval = secret_service_prompt_finish (test->service, result, &error); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED); g_assert_null (retval); g_object_unref (result); g_clear_error (&error); /* Make sure everything completes */ egg_test_wait_idle (); g_object_unref (prompt); g_assert_null (prompt); } static void test_service_path (Test *test, gconstpointer unused) { GError *error = NULL; GAsyncResult *result = NULL; SecretPrompt *prompt; GVariant *retval; prompt = _secret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple"); secret_service_prompt (test->service, prompt, NULL, NULL, on_async_result, &result); g_assert_null (result); g_object_unref (prompt); egg_test_wait (); retval = secret_service_prompt_finish (test->service, result, &error); g_assert_no_error (error); g_assert_nonnull (retval); g_variant_unref (retval); g_object_unref (result); /* Make sure everything completes */ egg_test_wait_idle (); } static void null_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-prompt"); /* Suppress these messages in tests */ g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, null_log_handler, NULL); g_test_add ("/prompt/run", Test, "mock-service-prompt.py", setup, test_perform_run, teardown); g_test_add ("/prompt/perform-sync", Test, "mock-service-prompt.py", setup, test_perform_sync, teardown); g_test_add ("/prompt/perform-async", Test, "mock-service-prompt.py", setup, test_perform_async, teardown); g_test_add ("/prompt/perform-cancel", Test, "mock-service-prompt.py", setup, test_perform_cancel, teardown); g_test_add ("/prompt/perform-fail", Test, "mock-service-prompt.py", setup, test_perform_fail, teardown); g_test_add ("/prompt/perform-vanish", Test, "mock-service-prompt.py", setup, test_perform_vanish, teardown); g_test_add ("/prompt/result", Test, "mock-service-prompt.py", setup, test_prompt_result, teardown); g_test_add ("/prompt/window-id", Test, "mock-service-prompt.py", setup, test_prompt_window_id, teardown); g_test_add ("/prompt/service-sync", Test, "mock-service-prompt.py", setup, test_service_sync, teardown); g_test_add ("/prompt/service-async", Test, "mock-service-prompt.py", setup, test_service_async, teardown); g_test_add ("/prompt/service-path", Test, "mock-service-prompt.py", setup, test_service_path, teardown); g_test_add ("/prompt/service-fail", Test, "mock-service-prompt.py", setup, test_service_fail, teardown); return egg_tests_run_with_loop (); } 0707010000008B000081A400000000000000000000000167D9F0D90000091C000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/test-py-clear.py#!/usr/bin/env python # # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # import sys import unittest import gi gi.require_version('MockService', '0') gi.require_version('Secret', '1') from gi.repository import MockService as Mock from gi.repository import Secret, GLib STORE_SCHEMA = Secret.Schema.new("org.mock.Schema", Secret.SchemaFlags.NONE, { "number": Secret.SchemaAttributeType.INTEGER, "string": Secret.SchemaAttributeType.STRING, "even": Secret.SchemaAttributeType.BOOLEAN, } ) class TestRemove(unittest.TestCase): def setUp(self): Mock.start("mock-service-normal.py") def tearDown(self): Secret.Service.disconnect() Mock.stop() def testSynchronous(self): attributes = { "number": "1", "string": "one", "even": "false" } password = Secret.password_lookup_sync(STORE_SCHEMA, attributes, None) self.assertEqual("111", password) deleted = Secret.password_clear_sync(STORE_SCHEMA, attributes, None) self.assertEqual(True, deleted) def testSyncNotFound(self): attributes = { "number": "11", "string": "one", "even": "true" } password = Secret.password_lookup_sync(STORE_SCHEMA, attributes, None) self.assertEqual(None, password) deleted = Secret.password_clear_sync(STORE_SCHEMA, attributes, None) self.assertEqual(False, deleted) def testAsynchronous(self): loop = GLib.MainLoop(None) def on_result_ready(source, result, unused): loop.quit() deleted = Secret.password_clear_finish(result) self.assertEquals(True, deleted) Secret.password_clear(STORE_SCHEMA, { "number": "2", "string": "two" }, None, on_result_ready, None) loop.run() def testAsyncNotFound(self): loop = GLib.MainLoop(None) def on_result_ready(source, result, unused): loop.quit() deleted = Secret.password_clear_finish(result) self.assertEquals(False, deleted) Secret.password_clear(STORE_SCHEMA, { "number": "7", "string": "five" }, None, on_result_ready, None) loop.run() if __name__ == '__main__': unittest.main() 0707010000008C000081A400000000000000000000000167D9F0D9000007F3000000000000000000000000000000000000002D00000000libsecret-0.21.7/libsecret/test-py-lookup.py#!/usr/bin/env python # # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # import unittest import gi gi.require_version('MockService', '0') gi.require_version('Secret', '1') from gi.repository import MockService as Mock from gi.repository import Secret, GLib STORE_SCHEMA = Secret.Schema.new("org.mock.Schema", Secret.SchemaFlags.NONE, { "number": Secret.SchemaAttributeType.INTEGER, "string": Secret.SchemaAttributeType.STRING, "even": Secret.SchemaAttributeType.BOOLEAN, } ) class TestLookup(unittest.TestCase): def setUp(self): Mock.start("mock-service-normal.py") def tearDown(self): Secret.Service.disconnect() Mock.stop() def testSynchronous(self): password = Secret.password_lookup_sync (STORE_SCHEMA, { "number": "1", "even": "false" }, None) self.assertEqual("111", password) def testSyncNotFound(self): password = Secret.password_lookup_sync (STORE_SCHEMA, { "number": "5", "even": "true" }, None) self.assertEqual(None, password) def testAsynchronous(self): loop = GLib.MainLoop(None) def on_result_ready(source, result, unused): loop.quit() password = Secret.password_lookup_finish(result) self.assertEquals("222", password) Secret.password_lookup (STORE_SCHEMA, { "number": "2", "string": "two" }, None, on_result_ready, None) loop.run() def testAsyncNotFound(self): loop = GLib.MainLoop(None) def on_result_ready(source, result, unused): loop.quit() password = Secret.password_lookup_finish(result) self.assertEquals(None, password) Secret.password_lookup (STORE_SCHEMA, { "number": "7", "string": "five" }, None, on_result_ready, None) loop.run() if __name__ == '__main__': unittest.main() 0707010000008D000081A400000000000000000000000167D9F0D900000868000000000000000000000000000000000000002C00000000libsecret-0.21.7/libsecret/test-py-store.py#!/usr/bin/env python # # Copyright 2012 Red Hat Inc. # # 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 licence or (at # your option) any later version. # # See the included COPYING file for more information. # import unittest import gi gi.require_version('MockService', '0') gi.require_version('Secret', '1') from gi.repository import MockService as Mock from gi.repository import Secret, GLib STORE_SCHEMA = Secret.Schema.new("org.mock.Schema", Secret.SchemaFlags.NONE, { "number": Secret.SchemaAttributeType.INTEGER, "string": Secret.SchemaAttributeType.STRING, "even": Secret.SchemaAttributeType.BOOLEAN, } ) class TestStore(unittest.TestCase): def setUp(self): Mock.start("mock-service-normal.py") def tearDown(self): Secret.Service.disconnect() Mock.stop() def testSynchronous(self): attributes = { "number": "9", "string": "nine", "even": "false" } password = Secret.password_lookup_sync(STORE_SCHEMA, attributes, None) self.assertEqual(None, password) stored = Secret.password_store_sync(STORE_SCHEMA, attributes, Secret.COLLECTION_DEFAULT, "The number nine", "999", None) self.assertEqual(True, stored); password = Secret.password_lookup_sync(STORE_SCHEMA, attributes, None) self.assertEqual("999", password) def testAsynchronous(self): attributes = { "number": "888", "string": "eight", "even": "true" } password = Secret.password_lookup_sync(STORE_SCHEMA, attributes, None) self.assertEqual(None, password); loop = GLib.MainLoop(None) def on_result_ready(source, result, unused): loop.quit() stored = Secret.password_store_finish(result) self.assertEquals(True, stored) Secret.password_store(STORE_SCHEMA, attributes, None, "The number eight", "888", None, on_result_ready, None) loop.run() password = Secret.password_lookup_sync(STORE_SCHEMA, attributes, None) self.assertEqual("888", password) if __name__ == '__main__': unittest.main() 0707010000008E000081A400000000000000000000000167D9F0D900004AF5000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/test-service.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-collection.h" #include "secret-item.h" #include "secret-service.h" #include "secret-paths.h" #include "secret-private.h" #include "mock-service.h" #include "egg/egg-testing.h" #include #include #include typedef struct { SecretService *service; } Test; static void setup_mock (Test *test, gconstpointer data) { GError *error = NULL; const gchar *mock_script = data; mock_service_start (mock_script, &error); g_assert_no_error (error); } static void teardown_mock (Test *test, gconstpointer unused) { /* * Because the entire model of GDBus using another worker-thread * is shit and racy as hell. If I had more time I would fix GDBus not to segfault * during tests, but for now this is the best I can do. */ g_usleep (G_USEC_PER_SEC); secret_service_disconnect (); mock_service_stop (); while (g_main_context_iteration (NULL, FALSE)); } static void on_complete_get_result (GObject *source, GAsyncResult *result, gpointer user_data) { GAsyncResult **ret = user_data; g_assert_nonnull (ret); g_assert_null (*ret); *ret = g_object_ref (result); egg_test_wait_stop (); } static void test_get_sync (Test *test, gconstpointer data) { SecretService *service1; SecretService *service2; SecretService *service3; GError *error = NULL; /* Both these sohuld point to the same thing */ service1 = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); service2 = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (service2), (gpointer *)&service2); g_assert_true (SECRET_IS_SERVICE (service1)); g_assert_true (service1 == service2); g_object_unref (service1); g_assert_true (G_IS_OBJECT (service1)); g_object_unref (service2); secret_service_disconnect (); g_assert_null (service2); /* Services were disconnected, so this should create a new one */ service3 = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_true (SECRET_IS_SERVICE (service3)); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (service3), (gpointer *)&service3); g_object_unref (service3); /* Because the entire model of GDBus using another worker-thread is shite */ g_usleep (G_USEC_PER_SEC); secret_service_disconnect (); g_assert_null (service3); } static void test_get_async (Test *test, gconstpointer data) { SecretService *service1; SecretService *service2; SecretService *service3; GAsyncResult *result = NULL; GError *error = NULL; /* Both these sohuld point to the same thing */ secret_service_get (SECRET_SERVICE_NONE, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service1 = secret_service_get_finish (result, &error); g_assert_no_error (error); g_clear_object (&result); secret_service_get (SECRET_SERVICE_NONE, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service2 = secret_service_get_finish (result, &error); g_assert_no_error (error); g_clear_object (&result); g_object_add_weak_pointer (G_OBJECT (service2), (gpointer *)&service2); g_assert_true (SECRET_IS_SERVICE (service1)); g_assert_true (service1 == service2); g_object_unref (service1); g_assert_true (G_IS_OBJECT (service1)); g_object_unref (service2); secret_service_disconnect (); g_assert_null (service2); /* Services were unreffed, so this should create a new one */ secret_service_get (SECRET_SERVICE_NONE, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service3 = secret_service_get_finish (result, &error); g_assert_no_error (error); g_clear_object (&result); g_object_add_weak_pointer (G_OBJECT (service3), (gpointer *)&service3); g_object_unref (service3); secret_service_disconnect (); g_assert_null (service3); } static void test_get_more_sync (Test *test, gconstpointer data) { SecretService *service; SecretService *service2; GError *error = NULL; const gchar *path; GList *collections; service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_NONE); service2 = secret_service_get_sync (SECRET_SERVICE_LOAD_COLLECTIONS, NULL, &error); g_assert_no_error (error); g_assert_true (SECRET_IS_SERVICE (service)); g_assert_true (service == service2); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_LOAD_COLLECTIONS); collections = secret_service_get_collections (service); g_assert_nonnull (collections); g_list_free_full (collections, g_object_unref); g_object_unref (service2); service2 = secret_service_get_sync (SECRET_SERVICE_OPEN_SESSION, NULL, &error); g_assert_no_error (error); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS); path = secret_service_get_session_dbus_path (service); g_assert_nonnull (path); g_object_unref (service2); g_object_unref (service); secret_service_disconnect (); g_assert_null (service); } static void test_get_more_async (Test *test, gconstpointer data) { GAsyncResult *result = NULL; SecretService *service; GError *error = NULL; const gchar *path; GList *collections; secret_service_get (SECRET_SERVICE_LOAD_COLLECTIONS | SECRET_SERVICE_OPEN_SESSION, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service = secret_service_get_finish (result, &error); g_assert_no_error (error); g_object_unref (result); result = NULL; g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS); path = secret_service_get_session_dbus_path (service); g_assert_nonnull (path); collections = secret_service_get_collections (service); g_assert_nonnull (collections); g_list_free_full (collections, g_object_unref); g_object_unref (service); secret_service_disconnect (); g_assert_null (service); /* Now get a session with just collections */ secret_service_get (SECRET_SERVICE_LOAD_COLLECTIONS, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service = secret_service_get_finish (result, &error); g_assert_no_error (error); g_object_unref (result); g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_LOAD_COLLECTIONS); path = secret_service_get_session_dbus_path (service); g_assert_null (path); collections = secret_service_get_collections (service); g_assert_nonnull (collections); g_list_free_full (collections, g_object_unref); g_object_unref (service); secret_service_disconnect (); g_assert_null (service); } static void test_open_sync (Test *test, gconstpointer data) { SecretService *service1; SecretService *service2; GError *error = NULL; /* Both these sohuld point to different things */ service1 = secret_service_open_sync (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (service1), (gpointer *)&service1); service2 = secret_service_open_sync (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (service2), (gpointer *)&service2); g_assert_true (SECRET_IS_SERVICE (service1)); g_assert_true (SECRET_IS_SERVICE (service2)); g_assert_true (service1 != service2); g_object_unref (service1); g_assert_null (service1); g_object_unref (service2); g_assert_null (service2); } static void test_open_async (Test *test, gconstpointer data) { SecretService *service1; SecretService *service2; GAsyncResult *result = NULL; GError *error = NULL; /* Both these sohuld point to different things */ secret_service_open (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_NONE, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service1 = secret_service_open_finish (result, &error); g_assert_no_error (error); g_clear_object (&result); g_object_add_weak_pointer (G_OBJECT (service1), (gpointer *)&service1); secret_service_open (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_NONE, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service2 = secret_service_open_finish (result, &error); g_assert_no_error (error); g_clear_object (&result); g_object_add_weak_pointer (G_OBJECT (service2), (gpointer *)&service2); g_assert_true (SECRET_IS_SERVICE (service1)); g_assert_true (SECRET_IS_SERVICE (service2)); g_assert_true (service1 != service2); g_object_unref (service1); g_assert_null (service1); g_object_unref (service2); g_assert_null (service2); } static void test_open_more_sync (Test *test, gconstpointer data) { SecretService *service; GError *error = NULL; const gchar *path; GList *collections; service = secret_service_open_sync (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_assert_true (SECRET_IS_SERVICE (service)); g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_NONE); g_assert_null (secret_service_get_collections (service)); g_assert_null (secret_service_get_session_dbus_path (service)); g_object_unref (service); g_assert_null (service); service = secret_service_open_sync (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_LOAD_COLLECTIONS, NULL, &error); g_assert_no_error (error); g_assert_true (SECRET_IS_SERVICE (service)); g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_LOAD_COLLECTIONS); collections = secret_service_get_collections (service); g_assert_nonnull (collections); g_list_free_full (collections, g_object_unref); g_assert_null (secret_service_get_session_dbus_path (service)); g_object_unref (service); g_assert_null (service); service = secret_service_open_sync (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_OPEN_SESSION, NULL, &error); g_assert_no_error (error); g_assert_true (SECRET_IS_SERVICE (service)); g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_OPEN_SESSION); g_assert_null (secret_service_get_collections (service)); path = secret_service_get_session_dbus_path (service); g_assert_nonnull (path); g_object_unref (service); g_assert_null (service); } static void test_open_more_async (Test *test, gconstpointer data) { GAsyncResult *result = NULL; SecretService *service; GError *error = NULL; const gchar *path; GList *collections; secret_service_open (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_LOAD_COLLECTIONS | SECRET_SERVICE_OPEN_SESSION, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service = secret_service_open_finish (result, &error); g_assert_no_error (error); g_object_unref (result); result = NULL; g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS); path = secret_service_get_session_dbus_path (service); g_assert_nonnull (path); collections = secret_service_get_collections (service); g_assert_nonnull (collections); g_list_free_full (collections, g_object_unref); g_object_unref (service); g_assert_null (service); /* Now get a session with just collections */ secret_service_open (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_LOAD_COLLECTIONS, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service = secret_service_open_finish (result, &error); g_assert_no_error (error); g_object_unref (result); g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); g_assert_cmpuint (secret_service_get_flags (service), ==, SECRET_SERVICE_LOAD_COLLECTIONS); path = secret_service_get_session_dbus_path (service); g_assert_null (path); collections = secret_service_get_collections (service); g_assert_nonnull (collections); g_list_free_full (collections, g_object_unref); g_object_unref (service); g_assert_null (service); } static void test_connect_async (Test *test, gconstpointer used) { GError *error = NULL; GAsyncResult *result = NULL; SecretService *service; const gchar *path; /* Passing false, not session */ secret_service_get (SECRET_SERVICE_NONE, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service = secret_service_get_finish (result, &error); g_assert_true (SECRET_IS_SERVICE (service)); g_assert_no_error (error); g_object_unref (result); g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); path = secret_service_get_session_dbus_path (service); g_assert_null (path); g_object_unref (service); secret_service_disconnect (); g_assert_null (service); } static void test_connect_ensure_async (Test *test, gconstpointer used) { GError *error = NULL; GAsyncResult *result = NULL; SecretService *service; const gchar *path; /* Passing true, ensures session is established */ secret_service_get (SECRET_SERVICE_OPEN_SESSION, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); service = secret_service_get_finish (result, &error); g_assert_no_error (error); g_assert_true (SECRET_IS_SERVICE (service)); g_object_unref (result); g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); path = secret_service_get_session_dbus_path (service); g_assert_nonnull (path); g_object_unref (service); secret_service_disconnect (); g_assert_null (service); } static void test_ensure_sync (Test *test, gconstpointer used) { GError *error = NULL; SecretService *service; SecretServiceFlags flags; gboolean ret; /* Passing true, ensures session is established */ service = secret_service_open_sync (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_assert_nonnull (service); g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); flags = secret_service_get_flags (service); g_assert_cmpuint (flags, ==, SECRET_SERVICE_NONE); ret = secret_service_load_collections_sync (service, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_object_get (service, "flags", &flags, NULL); g_assert_cmpuint (flags, ==, SECRET_SERVICE_LOAD_COLLECTIONS); ret = secret_service_ensure_session_sync (service, NULL, &error); g_assert_no_error (error); g_assert_true (ret); flags = secret_service_get_flags (service); g_assert_cmpuint (flags, ==, SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS); g_object_unref (service); g_assert_null (service); } static void test_ensure_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; SecretServiceFlags flags; SecretService *service; GError *error = NULL; gboolean ret; /* Passing true, ensures session is established */ service = secret_service_open_sync (SECRET_TYPE_SERVICE, NULL, SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_assert_nonnull (service); flags = secret_service_get_flags (service); g_assert_cmpuint (flags, ==, SECRET_SERVICE_NONE); secret_service_load_collections (service, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); ret = secret_service_load_collections_finish (service, result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); result = NULL; g_object_get (service, "flags", &flags, NULL); g_assert_cmpuint (flags, ==, SECRET_SERVICE_LOAD_COLLECTIONS); secret_service_ensure_session (service, NULL, on_complete_get_result, &result); g_assert_null (result); egg_test_wait (); ret = secret_service_ensure_session_finish (service, result, &error); g_assert_no_error (error); g_assert_true (ret); g_object_unref (result); result = NULL; g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); flags = secret_service_get_flags (service); g_assert_cmpuint (flags, ==, SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS); g_object_unref (service); g_assert_null (service); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-service"); g_test_add ("/service/get-sync", Test, "mock-service-normal.py", setup_mock, test_get_sync, teardown_mock); g_test_add ("/service/get-async", Test, "mock-service-normal.py", setup_mock, test_get_async, teardown_mock); g_test_add ("/service/get-more-sync", Test, "mock-service-normal.py", setup_mock, test_get_more_sync, teardown_mock); g_test_add ("/service/get-more-async", Test, "mock-service-normal.py", setup_mock, test_get_more_async, teardown_mock); g_test_add ("/service/open-sync", Test, "mock-service-normal.py", setup_mock, test_open_sync, teardown_mock); g_test_add ("/service/open-async", Test, "mock-service-normal.py", setup_mock, test_open_async, teardown_mock); g_test_add ("/service/open-more-sync", Test, "mock-service-normal.py", setup_mock, test_open_more_sync, teardown_mock); g_test_add ("/service/open-more-async", Test, "mock-service-normal.py", setup_mock, test_open_more_async, teardown_mock); g_test_add ("/service/connect-sync", Test, "mock-service-normal.py", setup_mock, test_connect_async, teardown_mock); g_test_add ("/service/connect-ensure-sync", Test, "mock-service-normal.py", setup_mock, test_connect_ensure_async, teardown_mock); g_test_add ("/service/ensure-sync", Test, "mock-service-normal.py", setup_mock, test_ensure_sync, teardown_mock); g_test_add ("/service/ensure-async", Test, "mock-service-normal.py", setup_mock, test_ensure_async, teardown_mock); return egg_tests_run_with_loop (); } 0707010000008F000081A400000000000000000000000167D9F0D900001C5F000000000000000000000000000000000000002A00000000libsecret-0.21.7/libsecret/test-session.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-item.h" #include "secret-service.h" #include "secret-paths.h" #include "secret-private.h" #include "mock-service.h" #include "egg/egg-testing.h" #include #include #include #ifdef WITH_CRYPTO #define SESSION_ALGO "dh-ietf1024-sha256-aes128-cbc-pkcs7" #else #define SESSION_ALGO "plain" #endif typedef struct { SecretService *service; } Test; static void setup (Test *test, gconstpointer data) { GError *error = NULL; const gchar *mock_script = data; mock_service_start (mock_script, &error); g_assert_no_error (error); test->service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert_no_error (error); g_object_add_weak_pointer (G_OBJECT (test->service), (gpointer *)&test->service); } static void teardown (Test *test, gconstpointer unused) { g_object_unref (test->service); secret_service_disconnect (); g_assert_null (test->service); mock_service_stop (); } static void test_ensure (Test *test, gconstpointer unused) { GError *error = NULL; gboolean ret; g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), ==, NULL); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, NULL); ret = secret_service_ensure_session_sync (test->service, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, SESSION_ALGO); } static void test_ensure_twice (Test *test, gconstpointer unused) { GError *error = NULL; gchar *path; gboolean ret; g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), ==, NULL); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, NULL); ret = secret_service_ensure_session_sync (test->service, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, SESSION_ALGO); path = g_strdup (secret_service_get_session_dbus_path (test->service)); ret = secret_service_ensure_session_sync (test->service, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), ==, path); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, SESSION_ALGO); g_free (path); } static void test_ensure_plain (Test *test, gconstpointer unused) { GError *error = NULL; gboolean ret; g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), ==, NULL); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, NULL); ret = secret_service_ensure_session_sync (test->service, NULL, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, "plain"); } static void on_complete_get_result (GObject *source, GAsyncResult *result, gpointer user_data) { GAsyncResult **ret = user_data; g_assert_nonnull (ret); g_assert_null (*ret); *ret = g_object_ref (result); egg_test_wait_stop (); } static void test_ensure_async_plain (Test *test, gconstpointer unused) { GAsyncResult *result = NULL; GError *error = NULL; gboolean ret; secret_service_ensure_session (test->service, NULL, on_complete_get_result, &result); egg_test_wait (); g_assert_true (G_IS_ASYNC_RESULT (result)); ret = secret_service_ensure_session_finish (test->service, result, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, "plain"); g_object_unref (result); } static void test_ensure_async_aes (Test *test, gconstpointer unused) { GAsyncResult *result = NULL; GError *error = NULL; gboolean ret; secret_service_ensure_session (test->service, NULL, on_complete_get_result, &result); egg_test_wait_until (500); g_assert_true (G_IS_ASYNC_RESULT (result)); ret = secret_service_ensure_session_finish (test->service, result, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, SESSION_ALGO); g_object_unref (result); } static void test_ensure_async_twice (Test *test, gconstpointer unused) { GAsyncResult *result = NULL; GError *error = NULL; gboolean ret; gchar *path; secret_service_ensure_session (test->service, NULL, on_complete_get_result, &result); egg_test_wait_until (500); g_assert_true (G_IS_ASYNC_RESULT (result)); ret = secret_service_ensure_session_finish (test->service, result, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, "plain"); g_object_unref (result); result = NULL; path = g_strdup (secret_service_get_session_dbus_path (test->service)); secret_service_ensure_session (test->service, NULL, on_complete_get_result, &result); egg_test_wait_until (500); g_assert_true (G_IS_ASYNC_RESULT (result)); ret = secret_service_ensure_session_finish (test->service, result, &error); g_assert_no_error (error); g_assert_true (ret); g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), ==, path); g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, "plain"); g_object_unref (result); g_free (path); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-session"); g_test_add ("/session/ensure-aes", Test, "mock-service-normal.py", setup, test_ensure, teardown); g_test_add ("/session/ensure-twice", Test, "mock-service-normal.py", setup, test_ensure_twice, teardown); g_test_add ("/session/ensure-plain", Test, "mock-service-only-plain.py", setup, test_ensure_plain, teardown); g_test_add ("/session/ensure-async-aes", Test, "mock-service-normal.py", setup, test_ensure_async_aes, teardown); g_test_add ("/session/ensure-async-plain", Test, "mock-service-only-plain.py", setup, test_ensure_async_plain, teardown); g_test_add ("/session/ensure-async-twice", Test, "mock-service-only-plain.py", setup, test_ensure_async_twice, teardown); return egg_tests_run_with_loop (); } 07070100000090000081A400000000000000000000000167D9F0D900001848000000000000000000000000000000000000002F00000000libsecret-0.21.7/libsecret/test-vala-lang.vala/* * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. */ Secret.Schema schema; Secret.Schema no_name_schema; private void test_attributes_validate () { try { var attributes = new GLib.HashTable (GLib.str_hash, GLib.str_equal); attributes["even"] = "false"; attributes["string"] = "one"; attributes["number"] = "1"; bool valid = Secret.attributes_validate (schema, attributes); GLib.assert (valid == true); } catch ( GLib.Error e ) { GLib.error (e.message); } } private void test_lookup_sync () { try { string? password = Secret.password_lookup_sync (schema, null, "even", false, "string", "one", "number", 1); GLib.assert (password == "111"); } catch ( GLib.Error e ) { GLib.error (e.message); } } public async void test_lookup_async_ex () { try { string? password = yield Secret.password_lookup (schema, null, "even", false, "string", "one", "number", 1); GLib.assert (password == "111"); } catch ( GLib.Error e ) { GLib.error (e.message); } } private void test_lookup_async () { var loop = new GLib.MainLoop (); test_lookup_async_ex.begin ((obj, async_res) => { loop.quit (); }); loop.run (); } private void test_lookup_no_name () { try { string? password = Secret.password_lookup_sync (schema, null, "number", 5); GLib.assert (password == null); password = Secret.password_lookup_sync (no_name_schema, null, "number", 5); GLib.assert (password == "555"); } catch ( GLib.Error e ) { GLib.error (e.message); } } private void test_store_sync () { try { var attributes = new GLib.HashTable (GLib.str_hash, GLib.str_equal); attributes["even"] = "false"; attributes["string"] = "nine"; attributes["number"] = "9"; string? password = Secret.password_lookupv_sync (schema, attributes); GLib.assert (password == null); bool stored = Secret.password_storev_sync (schema, attributes, Secret.COLLECTION_DEFAULT, "The number ", "999"); GLib.assert (stored); password = Secret.password_lookupv_sync (schema, attributes); GLib.assert (password == "999"); } catch ( GLib.Error e ) { GLib.error (e.message); } } private async void test_store_async_ex () { var attributes = new GLib.HashTable (GLib.str_hash, GLib.str_equal); attributes["even"] = "true"; attributes["string"] = "eight"; attributes["number"] = "8"; try { string? password = yield Secret.password_lookupv (schema, attributes, null); GLib.assert (password == null); bool stored = yield Secret.password_storev (schema, attributes, Secret.COLLECTION_DEFAULT, "The number nine", "999", null); GLib.assert (stored); password = yield Secret.password_lookupv (schema, attributes, null); GLib.assert (password == "999"); } catch ( GLib.Error e ) { GLib.error (e.message); } } private void test_store_async () { var loop = new GLib.MainLoop (); test_store_async_ex.begin ((obj, async_res) => { loop.quit (); }); loop.run (); } private void test_clear_sync () { try { var attributes = new GLib.HashTable (GLib.str_hash, GLib.str_equal); attributes["even"] = "false"; attributes["string"] = "nine"; attributes["number"] = "9"; string? password = Secret.password_lookupv_sync (schema, attributes); GLib.assert (password == "999"); bool removed = Secret.password_clearv_sync (schema, attributes, null); GLib.assert (removed); password = Secret.password_lookupv_sync (schema, attributes); GLib.assert (password == null); } catch ( GLib.Error e ) { GLib.error (e.message); } } private async void test_clear_async_ex () { var attributes = new GLib.HashTable (GLib.str_hash, GLib.str_equal); attributes["even"] = "true"; attributes["string"] = "eight"; attributes["number"] = "8"; try { string? password = yield Secret.password_lookupv (schema, attributes, null); GLib.assert (password == "999"); bool removed = yield Secret.password_clearv (schema, attributes, null); GLib.assert (removed); password = yield Secret.password_lookupv (schema, attributes, null); GLib.assert (password == null); } catch ( GLib.Error e ) { GLib.error (e.message); } } private void test_clear_async () { var loop = new GLib.MainLoop (); test_clear_async_ex.begin ((obj, async_res) => { loop.quit (); }); loop.run (); } private static int main (string[] args) { GLib.Test.init (ref args); try { MockService.start ("mock-service-normal.py"); } catch ( GLib.Error e ) { GLib.error ("Unable to start mock service: %s", e.message); } { schema = new Secret.Schema ("org.mock.Schema", Secret.SchemaFlags.NONE, "number", Secret.SchemaAttributeType.INTEGER, "string", Secret.SchemaAttributeType.STRING, "even", Secret.SchemaAttributeType.BOOLEAN); no_name_schema = new Secret.Schema ("unused.Schema.Name", Secret.SchemaFlags.DONT_MATCH_NAME, "number", Secret.SchemaAttributeType.INTEGER, "string", Secret.SchemaAttributeType.STRING); } GLib.Test.add_func ("/vala/attributes/validate", test_attributes_validate); GLib.Test.add_func ("/vala/lookup/sync", test_lookup_sync); GLib.Test.add_func ("/vala/lookup/async", test_lookup_async); GLib.Test.add_func ("/vala/lookup/no-name", test_lookup_no_name); GLib.Test.add_func ("/vala/store/sync", test_store_sync); GLib.Test.add_func ("/vala/store/async", test_store_async); GLib.Test.add_func ("/vala/clear/sync", test_clear_sync); GLib.Test.add_func ("/vala/clear/async", test_clear_async); var res = GLib.Test.run (); Secret.Service.disconnect (); MockService.stop (); schema = null; return res; } 07070100000091000081A400000000000000000000000167D9F0D9000003F1000000000000000000000000000000000000003300000000libsecret-0.21.7/libsecret/test-vala-unstable.vala/* * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. */ private void test_read_alias () { try { var service = Secret.Service.get_sync(Secret.ServiceFlags.NONE); var path = service.read_alias_dbus_path_sync("default", null); GLib.assert (path != null); } catch ( GLib.Error e ) { GLib.error (e.message); } } private static int main (string[] args) { GLib.Test.init (ref args); try { MockService.start ("mock-service-normal.py"); } catch ( GLib.Error e ) { GLib.error ("Unable to start mock service: %s", e.message); } GLib.Test.add_func ("/vala/unstable/read-alias", test_read_alias); var res = GLib.Test.run (); Secret.Service.disconnect (); MockService.stop (); return res; } 07070100000092000081A400000000000000000000000167D9F0D90000160A000000000000000000000000000000000000002800000000libsecret-0.21.7/libsecret/test-value.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. */ #include "config.h" #undef G_DISABLE_ASSERT #include "secret-value.h" #include "secret-private.h" #include "egg/egg-testing.h" #include "egg/egg-secure-memory.h" #include #include #include EGG_SECURE_DECLARE (test_value); static void test_new (void) { SecretValue *value; gsize length; value = secret_value_new ("blahblah", 4, "text/plain"); g_assert_cmpstr (secret_value_get (value, &length), ==, "blah"); g_assert_cmpuint (length, ==, 4); g_assert_cmpstr (secret_value_get_content_type (value), ==, "text/plain"); secret_value_unref (value); } static void test_new_terminated (void) { SecretValue *value; gsize length; value = secret_value_new ("blah", -1, "text/plain"); g_assert_cmpstr (secret_value_get (value, &length), ==, "blah"); g_assert_cmpuint (length, ==, 4); g_assert_cmpstr (secret_value_get_content_type (value), ==, "text/plain"); secret_value_unref (value); } static void test_new_full (void) { SecretValue *value; gchar *data = g_strdup ("blah"); gsize length; value = secret_value_new_full (data, 4, "text/plain", g_free); g_assert_cmpstr (secret_value_get (value, &length), ==, "blah"); g_assert_cmpuint (length, ==, 4); /* No copy done here */ g_assert_true (secret_value_get (value, NULL) == data); secret_value_unref (value); } static void test_new_full_terminated (void) { SecretValue *value; gchar *data = g_strdup ("blah"); gsize length; value = secret_value_new_full (data, -1, "text/plain", g_free); g_assert_cmpstr (secret_value_get (value, &length), ==, "blah"); g_assert_cmpuint (length, ==, 4); /* No copy done here */ g_assert_true (secret_value_get (value, NULL) == data); secret_value_unref (value); } static void test_new_empty (void) { SecretValue *value; const gchar *password; gsize length; value = secret_value_new (NULL, 0, "text/plain"); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 0); g_assert_cmpstr (password, ==, ""); secret_value_unref (value); value = secret_value_new ("", 0, "text/plain"); g_assert_nonnull (value); password = secret_value_get (value, &length); g_assert_cmpuint (length, ==, 0); g_assert_cmpstr (password, ==, ""); secret_value_unref (value); } static void test_ref_unref (void) { SecretValue *value; SecretValue *value2; gsize length; value = secret_value_new ("blah", 4, "text/plain"); value2 = secret_value_ref(value); secret_value_unref (value); g_assert_cmpstr (secret_value_get (value2, &length), ==, "blah"); g_assert_cmpuint (length, ==, 4); secret_value_unref (value2); } static void test_boxed (void) { SecretValue *value; SecretValue *value2; gsize length; value = secret_value_new ("blah", 4, "text/plain"); value2 = g_boxed_copy (SECRET_TYPE_VALUE, value); g_boxed_free (SECRET_TYPE_VALUE, value); g_assert_cmpstr (secret_value_get (value2, &length), ==, "blah"); g_assert_cmpuint (length, ==, 4); g_boxed_free (SECRET_TYPE_VALUE, value2); } static void test_to_password (void) { SecretValue *value; gchar *password; value = secret_value_new_full (egg_secure_strdup ("blah"), -1, "text/plain", egg_secure_free); password = _secret_value_unref_to_password (value); g_assert_cmpstr (password, ==, "blah"); egg_secure_free (password); } static void test_to_password_bad_destroy (void) { SecretValue *value; gchar *password; value = secret_value_new_full (g_strdup ("blah"), -1, "text/plain", g_free); password = _secret_value_unref_to_password (value); g_assert_cmpstr (password, ==, "blah"); egg_secure_free (password); } static void test_to_password_bad_content (void) { SecretValue *value; gchar *password; value = secret_value_new_full (g_strdup ("w\xFFooowhee"), -1, "application/octet-stream", g_free); password = _secret_value_unref_to_password (value); g_assert_cmpstr (password, ==, NULL); } static void test_to_password_extra_ref (void) { SecretValue *value; gchar *password; value = secret_value_new_full (egg_secure_strdup ("blah"), -1, "text/plain", egg_secure_free); secret_value_ref (value); password = _secret_value_unref_to_password (value); g_assert_cmpstr (password, ==, "blah"); egg_secure_free (password); secret_value_unref (value); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_set_prgname ("test-value"); g_test_add_func ("/value/new", test_new); g_test_add_func ("/value/new-terminated", test_new_terminated); g_test_add_func ("/value/new-full", test_new_full); g_test_add_func ("/value/new-full-terminated", test_new_full_terminated); g_test_add_func ("/value/new-empty", test_new_empty); g_test_add_func ("/value/ref-unref", test_ref_unref); g_test_add_func ("/value/boxed", test_boxed); g_test_add_func ("/value/to-password", test_to_password); g_test_add_func ("/value/to-password-bad-destroy", test_to_password_bad_destroy); g_test_add_func ("/value/to-password-bad-content", test_to_password_bad_content); g_test_add_func ("/value/to-password-extra-ref", test_to_password_extra_ref); return egg_tests_run_with_loop (); } 07070100000093000081A400000000000000000000000167D9F0D900000EB5000000000000000000000000000000000000001D00000000libsecret-0.21.7/meson.buildproject('libsecret', 'c', version: '0.21.7', license: 'LGPL-2.1-or-later AND GPL-2.0-or-later AND Apache-2.0', meson_version: '>= 0.50', ) gnome = import('gnome') i18n = import('i18n') pkg = import('pkgconfig') # API version api_version = '1.0.0' api_version_major = api_version.split('.')[0] api_version_minor = api_version.split('.')[1] api_version_micro = api_version.split('.')[2] libtool_version = '0.0.0' # Some variables config_h_dir = include_directories('.') build_dir = include_directories('build') libsecret_prefix = get_option('prefix') po_dir = meson.source_root() / 'po' # Dependencies min_glib_version = '2.44' glib_deps = [ dependency('glib-2.0', version: '>=' + min_glib_version), dependency('gio-2.0', version: '>=' + min_glib_version), dependency('gio-unix-2.0', version: '>=' + min_glib_version), ] with_gcrypt = false with_gnutls = false with_crypto = false crypto_deps = [] if get_option('crypto') == 'libgcrypt' min_libgcrypt_version = '1.2.2' gcrypt_dep = dependency( 'libgcrypt', version: '>=' + min_libgcrypt_version, ) with_gcrypt = true with_crypto = true crypto_deps += gcrypt_dep elif get_option('crypto') == 'gnutls' min_gnutls_version = '3.8.2' gnutls_dep = dependency( 'gnutls', version: '>=' + min_gnutls_version, ) with_gnutls = true with_crypto = true crypto_deps += gnutls_dep endif min_tss2_version = '3.0.3' tss2_esys = dependency('tss2-esys', version: '>=' + min_tss2_version, required: get_option('tpm2')) tss2_mu = dependency('tss2-mu', version: '>=' + min_tss2_version, required: get_option('tpm2')) tss2_rc = dependency('tss2-rc', version: '>=' + min_tss2_version, required: get_option('tpm2')) tss2_tctildr = dependency('tss2-tctildr', version: '>=' + min_tss2_version, required: get_option('tpm2')) tss2_deps = [] if tss2_esys.found() and tss2_mu.found() and tss2_rc.found() and tss2_tctildr.found() tss2_deps += [tss2_esys, tss2_mu, tss2_rc, tss2_tctildr] endif # Libraries math = meson.get_compiler('c').find_library('m') # Configuration conf = configuration_data() conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) conf.set_quoted('G_LOG_DOMAIN', meson.project_name()) conf.set_quoted('LOCALEDIR', libsecret_prefix / get_option('localedir')) conf.set_quoted('PACKAGE_NAME', meson.project_name()) conf.set_quoted('PACKAGE_STRING', meson.project_name()) conf.set_quoted('PACKAGE_VERSION', meson.project_version()) conf.set('WITH_GCRYPT', with_gcrypt) conf.set('WITH_GNUTLS', with_gnutls) conf.set('WITH_CRYPTO', with_crypto) conf.set('WITH_TPM', get_option('tpm2')) if with_gcrypt conf.set_quoted('LIBGCRYPT_VERSION', min_libgcrypt_version) endif if get_option('tpm2') conf.set_quoted('TSS2_VERSION', min_tss2_version) endif conf.set('WITH_DEBUG', get_option('debugging')) conf.set('_DEBUG', get_option('debugging')) conf.set('HAVE_MLOCK', meson.get_compiler('c').has_function('mlock')) if get_option('pam') conf.set_quoted('GNOME_KEYRING_DAEMON', get_option('prefix') / get_option('bindir') / 'gnome-keyring-daemon') endif configure_file(output: 'config.h', configuration: conf) # Test environment test_env = environment() test_env.set('abs_top_builddir', meson.build_root()) # Most tests require a D-Bus session, so try to wrap automatically with dbus-run-session dbus_run_session = find_program('dbus-run-session', required: false) if dbus_run_session.found() add_test_setup('dbus', exe_wrapper: dbus_run_session, is_default: true, ) else message('dbus-run-session not found. Please note that tests might fail if you don\'t set up a D-Bus session.') endif # Subfolders subdir('po') subdir('egg') subdir('libsecret') subdir('tool') subdir('docs') if get_option('pam') subdir('pam') endif subdir('bash-completion') 07070100000094000081A400000000000000000000000167D9F0D900000443000000000000000000000000000000000000002300000000libsecret-0.21.7/meson_options.txtoption('manpage', type: 'boolean', value: true, description: 'Build man pages', ) option('crypto', type: 'combo', choices: ['libgcrypt', 'gnutls', 'disabled'], value: 'libgcrypt', description: 'Backend library to implement transport encryption', ) option('debugging', type: 'boolean', value: false, description: 'Turn debugging on/off', ) option('vapi', type: 'boolean', value: true, description: 'Create VAPI file.', ) option('gtk_doc', type: 'boolean', value: true, description: 'Build reference documentation using gi-docgen', ) option('introspection', type: 'boolean', value: true, description: 'Create GIR file.', ) option('bashcompdir', type: 'string', value: '', description: 'Override default location for bash completion files', ) option('bash_completion', type: 'feature', value: 'auto', description: 'Install bash completion files', ) option('tpm2', type: 'boolean', value: false, description: 'With TPM2 Software Stack', ) option('pam', type: 'boolean', value: false, description: 'Build PAM module', ) 07070100000095000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000001500000000libsecret-0.21.7/pam07070100000096000081A400000000000000000000000167D9F0D90000042D000000000000000000000000000000000000002900000000libsecret-0.21.7/pam/gkd-control-codes.h/* * gnome-keyring * * Copyright (C) 2009 Stefan Walter * * 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, see * . */ #ifndef __GKD_CONTROL_CODES_H__ #define __GKD_CONTROL_CODES_H__ enum { GKD_CONTROL_OP_INITIALIZE, GKD_CONTROL_OP_UNLOCK, GKD_CONTROL_OP_CHANGE, GKD_CONTROL_OP_QUIT }; enum { GKD_CONTROL_RESULT_OK, GKD_CONTROL_RESULT_DENIED, GKD_CONTROL_RESULT_FAILED, GKD_CONTROL_RESULT_NO_DAEMON }; #endif /* __GKD_CONTROL_CODES_H__ */ 07070100000097000081A400000000000000000000000167D9F0D900002CE2000000000000000000000000000000000000002600000000libsecret-0.21.7/pam/gkr-pam-client.c/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gkr-pam-client.h - Simple code for communicating with daemon Copyright (C) 2007 Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, . Author: Stef Walter */ #include "config.h" #include "gkr-pam.h" #include "egg/egg-unix-credentials.h" #include "egg/egg-buffer.h" #include "gkd-control-codes.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_GETPEERUCRED) #include #endif #if defined(LOCAL_PEERCRED) #include #include #endif static int check_peer_same_uid (struct passwd *pwd, int sock) { uid_t uid = -1; /* * Certain OS require a message to be sent over the unix socket for the * otherside to get the process credentials. Most uncool. * * The normal gnome-keyring protocol accomodates this and the client * sends a message/byte before sending anything else. This only works * for the daemon verifying the client. * * This code here is used by a client to verify the daemon is running * as the right user. Since we cannot modify the protocol, this only * works on OSs that can do this credentials lookup transparently. */ /* Linux */ #if defined(SO_PEERCRED) struct ucred cr; socklen_t cr_len = sizeof (cr); if (getsockopt (sock, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 && cr_len == sizeof (cr)) { uid = cr.uid; } else { syslog (GKR_LOG_ERR, "could not get gnome-keyring-daemon socket credentials, " "(returned len %d/%d)\n", cr_len, (int) sizeof (cr)); return -1; } /* The BSDs */ #elif defined(LOCAL_PEERCRED) uid_t gid; struct xucred xuc; socklen_t xuc_len = sizeof (xuc); if (getsockopt (sock, SOL_SOCKET, LOCAL_PEERCRED, &xuc, &xuc_len) == 0 && xuc_len == sizeof (xuc)) { uid = xuc.cr_uid; } else { syslog (GKR_LOG_ERR, "could not get gnome-keyring-daemon socket credentials, " "(returned len %d/%d)\n", xuc_len, (int)sizeof (xuc)); return -1; } /* NOTE: Add more here */ #else syslog (GKR_LOG_WARN, "Cannot verify that the process to which we are passing the login" " password is genuinely running as the same user login: not supported on this OS."); uid = pwd->pw_uid; #endif if (uid != pwd->pw_uid) { syslog (GKR_LOG_ERR, "The gnome keyring socket is not running with the same " "credentials as the user login. Disconnecting."); return 0; } return 1; } static int write_credentials_byte (int sock) { for (;;) { if (egg_unix_credentials_write (sock) < 0) { if (errno == EINTR || errno == EAGAIN) continue; syslog (GKR_LOG_ERR, "couldn't send credentials to daemon: %s", strerror (errno)); return -1; } break; } return 0; } static int lookup_daemon (struct passwd *pwd, const char *control, struct sockaddr_un *addr) { struct stat st; if (strlen (control) + 1 > sizeof (addr->sun_path)) { syslog (GKR_LOG_ERR, "gkr-pam: address is too long for unix socket path: %s", control); return GKD_CONTROL_RESULT_FAILED; } memset (addr, 0, sizeof (*addr)); addr->sun_family = AF_UNIX; strcpy (addr->sun_path, control); /* A bunch of checks to make sure nothing funny is going on */ if (lstat (addr->sun_path, &st) < 0) { if (errno == ENOENT) return GKD_CONTROL_RESULT_NO_DAEMON; syslog (GKR_LOG_ERR, "Couldn't access gnome keyring socket: %s: %s", addr->sun_path, strerror (errno)); return GKD_CONTROL_RESULT_FAILED; } if (st.st_uid != pwd->pw_uid) { syslog (GKR_LOG_ERR, "The gnome keyring socket is not owned with the same " "credentials as the user login: %s", addr->sun_path); return GKD_CONTROL_RESULT_FAILED; } if (S_ISLNK(st.st_mode) || !S_ISSOCK(st.st_mode)) { syslog (GKR_LOG_ERR, "The gnome keyring socket is not a valid simple " "non-linked socket"); return GKD_CONTROL_RESULT_FAILED; } return GKD_CONTROL_RESULT_OK; } static int connect_daemon (struct passwd *pwd, struct sockaddr_un *addr, int *out_sock) { int sock; /* Now we connect */ sock = socket (AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { syslog (GKR_LOG_ERR, "couldn't create control socket: %s", strerror (errno)); return GKD_CONTROL_RESULT_FAILED; } /* close on exec */ fcntl (sock, F_SETFD, 1); if (connect (sock, (struct sockaddr *)addr, sizeof (*addr)) < 0) { if (errno == ECONNREFUSED) { close (sock); return GKD_CONTROL_RESULT_NO_DAEMON; } syslog (GKR_LOG_ERR, "couldn't connect to gnome-keyring-daemon socket at: %s: %s", addr->sun_path, strerror (errno)); close (sock); return GKD_CONTROL_RESULT_FAILED; } /* Verify the server is running as the right user */ if (check_peer_same_uid (pwd, sock) <= 0) { close (sock); return GKD_CONTROL_RESULT_FAILED; } /* This lets the server verify us */ if (write_credentials_byte (sock) < 0) { close (sock); return GKD_CONTROL_RESULT_FAILED; } *out_sock = sock; return GKD_CONTROL_RESULT_OK; } static void write_part (int fd, const unsigned char *data, int len, int *res) { assert (res); /* Already an error present */ if (*res != GKD_CONTROL_RESULT_OK) return; assert (data); while (len > 0) { int r = write (fd, data, len); if (r < 0) { if (errno == EAGAIN) continue; syslog (GKR_LOG_ERR, "couldn't send data to gnome-keyring-daemon: %s", strerror (errno)); *res = GKD_CONTROL_RESULT_FAILED; return; } data += r; len -= r; } } static int read_part (int fd, unsigned char *data, int len, int disconnect_ok) { int r, all; all = len; while (len > 0) { r = read (fd, data, len); if (r < 0) { if (errno == EAGAIN) continue; if (errno == ECONNRESET && disconnect_ok) return 0; syslog (GKR_LOG_ERR, "couldn't read data from gnome-keyring-daemon: %s", strerror (errno)); return -1; } if (r == 0) { if (disconnect_ok) return 0; syslog (GKR_LOG_ERR, "couldn't read data from gnome-keyring-daemon: %s", "unexpected end of data"); return -1; } data += r; len -= r; } return all; } static int keyring_daemon_op (struct passwd *pwd, struct sockaddr_un *addr, int op, int argc, const char *argv[]) { int ret = GKD_CONTROL_RESULT_OK; unsigned char buf[4]; int want_disconnect; int i, sock = -1; uint oplen, l; assert (addr); /* * We only support operations with zero or more strings * and an empty (only result code) return. */ assert (op == GKD_CONTROL_OP_CHANGE || op == GKD_CONTROL_OP_UNLOCK || op == GKD_CONTROL_OP_QUIT); ret = connect_daemon (pwd, addr, &sock); if (ret != GKD_CONTROL_RESULT_OK) goto done; /* Calculate the packet length */ oplen = 8; /* The packet size, and op code */ for (i = 0; i < argc; ++i) oplen += 4 + strlen (argv[i]); /* Write out the length, and op */ egg_buffer_encode_uint32 (buf, oplen); write_part (sock, buf, 4, &ret); egg_buffer_encode_uint32 (buf, op); write_part (sock, buf, 4, &ret); /* And now the arguments */ for (i = 0; i < argc; ++i) { if (argv[i] == NULL) l = 0x7FFFFFFF; else l = strlen (argv[i]); egg_buffer_encode_uint32 (buf, l); write_part (sock, buf, 4, &ret); if (argv[i] != NULL) write_part (sock, (unsigned char*)argv[i], l, &ret); } if (ret != GKD_CONTROL_RESULT_OK) goto done; /* * If we're asking the daemon to quit, then we expect * disconnects after we send the initial request */ want_disconnect = (op == GKD_CONTROL_OP_QUIT); /* Read the response length */ if (read_part (sock, buf, 4, want_disconnect) != 4) { ret = GKD_CONTROL_RESULT_FAILED; goto done; } /* We only support simple responses */ l = egg_buffer_decode_uint32 (buf); if (l != 8) { syslog (GKR_LOG_ERR, "invalid length response from gnome-keyring-daemon: %d", l); ret = GKD_CONTROL_RESULT_FAILED; goto done; } if (read_part (sock, buf, 4, want_disconnect) != 4) { ret = GKD_CONTROL_RESULT_FAILED; goto done; } ret = egg_buffer_decode_uint32 (buf); /* * If we asked the daemon to quit, wait for it to disconnect * by waiting until the socket disconnects from the other end. */ if (want_disconnect) { while (read (sock, buf, 4) > 0); } done: if (sock >= 0) close (sock); return ret; } int gkr_pam_client_run_operation (struct passwd *pwd, const char *control, int op, int argc, const char* argv[]) { struct sigaction ignpipe, oldpipe, defchld, oldchld; struct sockaddr_un addr; int res; pid_t pid; int status; /* Make dumb signals go away */ memset (&ignpipe, 0, sizeof (ignpipe)); memset (&oldpipe, 0, sizeof (oldpipe)); ignpipe.sa_handler = SIG_IGN; sigaction (SIGPIPE, &ignpipe, &oldpipe); memset (&defchld, 0, sizeof (defchld)); memset (&oldchld, 0, sizeof (oldchld)); defchld.sa_handler = SIG_DFL; sigaction (SIGCHLD, &defchld, &oldchld); res = lookup_daemon (pwd, control, &addr); if (res != GKD_CONTROL_RESULT_OK) goto out; if (pwd->pw_uid == getuid () && pwd->pw_gid == getgid () && pwd->pw_uid == geteuid () && pwd->pw_gid == getegid ()) { /* Already running as the right user, simple */ res = keyring_daemon_op (pwd, &addr, op, argc, argv); } else { /* Otherwise run a child process to do the dirty work */ switch (pid = fork ()) { case -1: syslog (GKR_LOG_ERR, "gkr-pam: couldn't fork: %s", strerror (errno)); res = GKD_CONTROL_RESULT_FAILED; break; case 0: /* Setup process credentials */ if (setgid (pwd->pw_gid) < 0 || setuid (pwd->pw_uid) < 0 || setegid (pwd->pw_gid) < 0 || seteuid (pwd->pw_uid) < 0) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't switch to user: %s: %s", pwd->pw_name, strerror (errno)); exit (GKD_CONTROL_RESULT_FAILED); } res = keyring_daemon_op (pwd, &addr, op, argc, argv); exit (res); return 0; /* Never reached */ default: /* wait for child process */ if (wait (&status) != pid) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't wait on child process: %s", strerror (errno)); res = GKD_CONTROL_RESULT_FAILED; } res = WEXITSTATUS (status); break; }; } out: sigaction (SIGCHLD, &oldchld, NULL); sigaction (SIGPIPE, &oldpipe, NULL); return res; } 07070100000098000081A400000000000000000000000167D9F0D900003D8A000000000000000000000000000000000000002600000000libsecret-0.21.7/pam/gkr-pam-module.c/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gkr-pam-module.h - A PAM module for unlocking the keyring Copyright (C) 2007 Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, . Author: Stef Walter */ /* * Inspired by pam_keyring: * W. Michael Petullo * Jonathan Nettleton */ #include "config.h" #include "gkr-pam.h" #include "gkd-control-codes.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(ENABLE_NLS) && defined(__linux__) #include #define gkr_pam_gettext(msgid) dgettext ("Linux-PAM", msgid) #else #define gkr_pam_gettext(msgid) (msgid) #endif /* ENABLE_NLS */ enum { ARG_AUTO_START = 1 << 0, ARG_IGNORE_SERVICE = 1 << 1, ARG_USE_AUTHTOK = 1 << 2 }; #define ENV_CONTROL "GNOME_KEYRING_CONTROL" #define MAX_CONTROL_SIZE (sizeof(((struct sockaddr_un *)0)->sun_path)) /* read & write ends of a pipe */ #define READ_END 0 #define WRITE_END 1 /* pre-set file descriptors */ #define STDIN 0 #define STDOUT 1 #define STDERR 2 /* Linux/BSD compatibility */ #ifndef PAM_AUTHTOK_RECOVER_ERR #define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR #endif #ifndef PAM_EXTERN #ifdef PAM_STATIC #define PAM_EXTERN static #else #define PAM_EXTERN extern #endif #endif /* ----------------------------------------------------------------------------- * HELPERS */ static void free_password (char *password) { volatile char *vp; size_t len; if (!password) return; /* Defeats some optimizations */ len = strlen (password); memset (password, 0xAA, len); memset (password, 0xBB, len); /* Defeats others */ vp = (volatile char*)password; while (*vp) *(vp++) = 0xAA; free (password); } /* check for list match. */ static int evaluate_inlist (const char *needle, const char *haystack) { const char *item; const char *remaining; if (!needle) return 0; remaining = haystack; for (;;) { item = strstr (remaining, needle); if (item == NULL) break; /* is it really the start of an item in the list? */ if (item == haystack || *(item - 1) == ',') { item += strlen (needle); /* is item really needle? */ if (*item == '\0' || *item == ',') return 1; } remaining = strchr (item, ','); if (remaining == NULL) break; /* skip ',' */ ++remaining; } return 0; } /* ----------------------------------------------------------------------------- * DAEMON MANAGEMENT */ static const char* get_any_env (pam_handle_t *ph, const char *name) { const char *env; assert (name); /* We only return non-empty variables */ /* * Some PAMs decide to strdup the return value, not sure * how we can detect this. */ env = pam_getenv (ph, name); if (env && env[0]) return env; env = getenv (name); if (env && env[0]) return env; return NULL; } static void cleanup_free_password (pam_handle_t *ph, void *data, int pam_end_status) { free_password (data); } /* control must be at least MAX_CONTROL_SIZE */ static int get_control_file (pam_handle_t *ph, char *control) { const char *control_root; const char *suffix; control_root = get_any_env (ph, ENV_CONTROL); if (control_root == NULL) { control_root = get_any_env (ph, "XDG_RUNTIME_DIR"); if (control_root == NULL) return GKD_CONTROL_RESULT_NO_DAEMON; suffix = "/keyring/control"; } else { suffix = "/control"; } if (strlen (control_root) + strlen (suffix) + 1 > MAX_CONTROL_SIZE) { syslog (GKR_LOG_ERR, "gkr-pam: address is too long for unix socket path: %s/%s", control, suffix); return GKD_CONTROL_RESULT_FAILED; } strcpy (control, control_root); strcat (control, suffix); return GKD_CONTROL_RESULT_OK; } static int unlock_keyring (pam_handle_t *ph, struct passwd *pwd, const char *password) { char control[MAX_CONTROL_SIZE]; int res; const char *argv[2]; assert (pwd); res = get_control_file(ph, control); if (res != GKD_CONTROL_RESULT_OK) { syslog (GKR_LOG_ERR, "gkr-pam: unable to locate daemon control file"); return PAM_SERVICE_ERR; } argv[0] = password; res = gkr_pam_client_run_operation (pwd, control, GKD_CONTROL_OP_UNLOCK, (argv[0] == NULL) ? 0 : 1, argv); /* An error unlocking */ if (res == GKD_CONTROL_RESULT_NO_DAEMON) { return PAM_SERVICE_ERR; } else if (res == GKD_CONTROL_RESULT_DENIED) { syslog (GKR_LOG_ERR, "gkr-pam: the password for the login keyring was invalid."); return PAM_SERVICE_ERR; } else if (res != GKD_CONTROL_RESULT_OK) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't unlock the login keyring."); return PAM_SERVICE_ERR; } syslog (GKR_LOG_INFO, "gkr-pam: unlocked login keyring"); return PAM_SUCCESS; } static int change_keyring_password (pam_handle_t *ph, struct passwd *pwd, const char *password, const char *original) { char control[MAX_CONTROL_SIZE]; const char *argv[3]; int res; assert (pwd); assert (password); assert (original); res = get_control_file(ph, control); if (res != GKD_CONTROL_RESULT_OK) { syslog (GKR_LOG_ERR, "gkr-pam: unable to locate daemon control file"); return PAM_SERVICE_ERR; } argv[0] = original; argv[1] = password; res = gkr_pam_client_run_operation (pwd, control, GKD_CONTROL_OP_CHANGE, 2, argv); if (res == GKD_CONTROL_RESULT_NO_DAEMON) { return PAM_SERVICE_ERR; /* No keyring, not an error. Will be created at initial authenticate. */ } else if (res == GKD_CONTROL_RESULT_DENIED) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't change password for the login keyring: the passwords didn't match."); return PAM_SERVICE_ERR; } else if (res != GKD_CONTROL_RESULT_OK) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't change password for the login keyring."); return PAM_SERVICE_ERR; } syslog (GKR_LOG_NOTICE, "gkr-pam: changed password for login keyring"); return PAM_SUCCESS; } /* ----------------------------------------------------------------------------- * PAM STUFF */ static int prompt_password (pam_handle_t *ph) { const struct pam_conv *conv; struct pam_message msg; struct pam_response *resp; const struct pam_message *msgs[1]; const void *item; char *password; int ret; /* Get the conversation function */ ret = pam_get_item (ph, PAM_CONV, &item); if (ret != PAM_SUCCESS) return ret; /* Setup a message */ memset (&msg, 0, sizeof (msg)); memset (&resp, 0, sizeof (resp)); msg.msg_style = PAM_PROMPT_ECHO_OFF; msg.msg = gkr_pam_gettext ("Password: "); msgs[0] = &msg; /* Call away */ conv = (const struct pam_conv*)item; ret = (conv->conv) (1, msgs, &resp, conv->appdata_ptr); if (ret != PAM_SUCCESS) return ret; password = resp[0].resp; free (resp); if (password == NULL) return PAM_CONV_ERR; /* Store it away for later use */ ret = pam_set_item (ph, PAM_AUTHTOK, password); free_password (password); if (ret == PAM_SUCCESS) ret = pam_get_item (ph, PAM_AUTHTOK, &item); return ret; } static uint parse_args (pam_handle_t *ph, int argc, const char **argv) { uint args = 0; const void *svc; int only_if_len; int i; svc = NULL; if (pam_get_item (ph, PAM_SERVICE, &svc) != PAM_SUCCESS) svc = NULL; only_if_len = strlen ("only_if="); /* Parse the arguments */ for (i = 0; i < argc; i++) { if (strcmp (argv[i], "auto_start") == 0) { args |= ARG_AUTO_START; } else if (strncmp (argv[i], "only_if=", only_if_len) == 0) { const char *value = argv[i] + only_if_len; if (!evaluate_inlist (svc, value)) args |= ARG_IGNORE_SERVICE; } else if (strcmp (argv[i], "use_authtok") == 0) { args |= ARG_USE_AUTHTOK; } else { syslog (GKR_LOG_WARN, "gkr-pam: invalid option: %s", argv[i]); } } return args; } static int stash_password_for_session (pam_handle_t *ph, const char *password) { if (pam_set_data (ph, "gkr_system_authtok", strdup (password), cleanup_free_password) != PAM_SUCCESS) { syslog (GKR_LOG_ERR, "gkr-pam: error stashing password for session"); return PAM_AUTHTOK_RECOVER_ERR; } return PAM_SUCCESS; } PAM_EXTERN int pam_sm_authenticate (pam_handle_t *ph, int unused, int argc, const char **argv) { struct passwd *pwd; const char *user, *password; uint args; int ret; args = parse_args (ph, argc, argv); if (args & ARG_IGNORE_SERVICE) return PAM_SUCCESS; /* Figure out and/or prompt for the user name */ ret = pam_get_user (ph, &user, NULL); if (ret != PAM_SUCCESS) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't get the user name: %s", pam_strerror (ph, ret)); return PAM_SERVICE_ERR; } pwd = getpwnam (user); if (!pwd) { syslog (GKR_LOG_ERR, "gkr-pam: error looking up user information"); return PAM_SERVICE_ERR; } /* Look up the password */ ret = pam_get_authtok (ph, PAM_AUTHTOK, &password, NULL); if (ret != PAM_SUCCESS || password == NULL) { if (ret == PAM_SUCCESS) syslog (GKR_LOG_WARN, "gkr-pam: no password is available for user"); else syslog (GKR_LOG_WARN, "gkr-pam: no password is available for user: %s", pam_strerror (ph, ret)); return PAM_SUCCESS; } ret = unlock_keyring (ph, pwd, password); if (ret != PAM_SUCCESS) { ret = stash_password_for_session (ph, password); syslog (GKR_LOG_INFO, "gkr-pam: stashed password to try later in open session"); } return ret; } PAM_EXTERN int pam_sm_open_session (pam_handle_t *ph, int flags, int argc, const char **argv) { const char *user = NULL, *password = NULL; struct passwd *pwd; int ret; uint args; args = parse_args (ph, argc, argv); if (args & ARG_IGNORE_SERVICE) return PAM_SUCCESS; /* Figure out the user name */ ret = pam_get_user (ph, &user, NULL); if (ret != PAM_SUCCESS) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't get the user name: %s", pam_strerror (ph, ret)); return PAM_SERVICE_ERR; } pwd = getpwnam (user); if (!pwd) { syslog (GKR_LOG_ERR, "gkr-pam: error looking up user information for: %s", user); return PAM_SERVICE_ERR; } /* Get the stored authtok here */ if (pam_get_data (ph, "gkr_system_authtok", (const void**)&password) != PAM_SUCCESS) { /* * No password, no worries, maybe this (PAM using) application * didn't do authentication, or is hopeless and wants to call * different PAM callbacks from different processes. * * No use complaining */ password = NULL; } if (args & ARG_AUTO_START || password) { ret = unlock_keyring (ph, pwd, password); if (ret != PAM_SUCCESS) return PAM_SERVICE_ERR; } /* Destroy the stored authtok once it has been used */ if (password && pam_set_data (ph, "gkr_system_authtok", NULL, NULL) != PAM_SUCCESS) { syslog (GKR_LOG_ERR, "gkr-pam: error destroying the password"); return PAM_SERVICE_ERR; } return PAM_SUCCESS; } PAM_EXTERN int pam_sm_setcred (pam_handle_t * ph, int flags, int argc, const char **argv) { return PAM_SUCCESS; } static int pam_chauthtok_preliminary (pam_handle_t *ph, struct passwd *pwd) { /* * If a super-user is changing a user's password then pam_unix.so * doesn't prompt for the user's current password, which means we * won't have access to that password to change the keyring password. * * So we could prompt for the current user's password except that * most software is broken in this regard, and doesn't use the * prompts properly. * * In addition how would we verify the user's password? We could * verify it against the Gnome Keyring, but if it is mismatched * from teh UNIX password then that would be super confusing. * * So we opt, just to send NULL along with the change password * request and have the user type in their current GNOME Keyring * password at an explanatory prompt. */ return PAM_IGNORE; } static int pam_chauthtok_update (pam_handle_t *ph, struct passwd *pwd, uint args) { const char *password, *original; int ret; ret = pam_get_authtok (ph, PAM_AUTHTOK, &password, NULL); if (ret != PAM_SUCCESS) password = NULL; ret = pam_get_authtok (ph, PAM_OLDAUTHTOK, &original, NULL); if (ret != PAM_SUCCESS || original == NULL) { syslog (GKR_LOG_WARN, "gkr-pam: couldn't update the login keyring password: %s", "no old password was entered"); if (password) stash_password_for_session (ph, password); return PAM_IGNORE; } if (password == NULL) { /* No password was set, and we can't prompt for it */ if (args & ARG_USE_AUTHTOK) { syslog (GKR_LOG_ERR, "gkr-pam: no password set, and use_authtok was specified"); return PAM_AUTHTOK_RECOVER_ERR; } /* No password was entered, prompt for it */ ret = prompt_password (ph); if (ret != PAM_SUCCESS) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't get the password from user: %s", pam_strerror (ph, ret)); return PAM_AUTH_ERR; } ret = pam_get_authtok (ph, PAM_AUTHTOK, &password, NULL); if (ret != PAM_SUCCESS || password == NULL) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't get the password from user: %s", ret == PAM_SUCCESS ? "password was null" : pam_strerror (ph, ret)); return PAM_AUTHTOK_RECOVER_ERR; } } ret = change_keyring_password (ph, pwd, password, original); if (ret != PAM_SUCCESS) { /* Store the password for our session handler */ stash_password_for_session (ph, password); syslog (GKR_LOG_INFO, "gkr-pam: stashed password to try later in open session"); } return ret; } PAM_EXTERN int pam_sm_close_session (pam_handle_t *ph, int flags, int argc, const char **argv) { /* Nothing to do, but we have to have this function exported */ return PAM_SUCCESS; } PAM_EXTERN int pam_sm_chauthtok (pam_handle_t *ph, int flags, int argc, const char **argv) { const char *user; struct passwd *pwd; uint args; int ret; args = parse_args (ph, argc, argv); if (args & ARG_IGNORE_SERVICE) return PAM_SUCCESS; /* Figure out and/or prompt for the user name */ ret = pam_get_user (ph, &user, NULL); if (ret != PAM_SUCCESS) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't get the user name: %s", pam_strerror (ph, ret)); return PAM_SERVICE_ERR; } pwd = getpwnam (user); if (!pwd) { syslog (GKR_LOG_ERR, "gkr-pam: error looking up user information for: %s", user); return PAM_SERVICE_ERR; } if (flags & PAM_PRELIM_CHECK) return pam_chauthtok_preliminary (ph, pwd); else if (flags & PAM_UPDATE_AUTHTOK) return pam_chauthtok_update (ph, pwd, args); else return PAM_IGNORE; } 07070100000099000081A400000000000000000000000167D9F0D900000591000000000000000000000000000000000000001F00000000libsecret-0.21.7/pam/gkr-pam.h/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gkr-pam.h - Common PAM definitions Copyright (C) 2007 Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, . Author: Stef Walter */ #ifndef GKRPAM_H_ #define GKRPAM_H_ #include #ifndef LOG_AUTHPRIV #define LOG_AUTHPRIV LOG_AUTH #endif #define GKR_LOG_ERR (LOG_ERR | LOG_AUTHPRIV) #define GKR_LOG_WARN (LOG_WARNING | LOG_AUTHPRIV) #define GKR_LOG_NOTICE (LOG_NOTICE | LOG_AUTHPRIV) #define GKR_LOG_INFO (LOG_INFO | LOG_AUTHPRIV) int gkr_pam_client_run_operation (struct passwd *pwd, const char *socket, int op, int argc, const char* argv[]); #endif /*GKRPAM_H_*/ 0707010000009A000081A400000000000000000000000167D9F0D90000033E000000000000000000000000000000000000002100000000libsecret-0.21.7/pam/meson.build# pam source pam = dependency('pam', required: true) pam_gnome_keyring = shared_library('pam_gnome_keyring', sources: [ 'gkr-pam-module.c', 'gkr-pam-client.c', ], dependencies: [ pam, glib_deps, ], include_directories: config_h_dir, link_with: libegg, c_args: [ '-D_GNU_SOURCE', ], name_prefix: '', ) # pam tests pam_wrapper = dependency('pam_wrapper', required: true) libpamtest = dependency('libpamtest', required: true) subdir('servicedir') test_bin = executable('pam_test', sources: [ 'test-pam.c', ], dependencies: [ libpamtest, glib_deps, ], ) test('pam-test', test_bin, env: { 'LD_PRELOAD': 'libpam_wrapper.so', 'PAM_WRAPPER': '1', 'PAM_WRAPPER_DEBUGLEVEL': '5', 'PAM_WRAPPER_SERVICE_DIR': meson.current_build_dir() + '/servicedir', }, ) 0707010000009B000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000002000000000libsecret-0.21.7/pam/servicedir0707010000009C000081A400000000000000000000000167D9F0D900000114000000000000000000000000000000000000002C00000000libsecret-0.21.7/pam/servicedir/meson.buildcustom_target('pam-test-service', command: 'true', output: 'null', depend_files: configure_file( input: 'pam-test-service.in', output: 'pam-test-service', configuration: configuration_data({ 'KEYRING_PAM': pam_gnome_keyring.full_path(), }), ), ) 0707010000009D000081A400000000000000000000000167D9F0D90000006F000000000000000000000000000000000000003400000000libsecret-0.21.7/pam/servicedir/pam-test-service.inauth required @KEYRING_PAM@ password required @KEYRING_PAM@ session required @KEYRING_PAM@ 0707010000009E000081A400000000000000000000000167D9F0D900001374000000000000000000000000000000000000002000000000libsecret-0.21.7/pam/test-pam.c/* * libsecret * * Copyright (C) 2023 GNOME Foundation Inc. * * 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 copies of the GNU General Public License and * the GNU Lesser General Public License along with this program. If * not, see http://www.gnu.org/licenses/. * * Author: Dhanuka Warusadura */ #include #include #include #include #include #include #define SERVICE "pam-test-service" #define BUFFER_SIZE 100 typedef struct { gchar *control_path; GSocketAddress *address; GSocketService *service; GThread *pam_test; gboolean success; } Test; static gchar dir_path[] = "/tmp/pam_test_XXXXXX"; static gboolean is_bytes_exchanged (GSocketService *service, GSocketConnection *connection, GObject *source_object, gpointer data) { Test *test = data; GInputStream *input; GError *error = NULL; char buffer[BUFFER_SIZE + 1]; g_printf ("Incoming signal detected\n"); if (g_socket_service_is_active (service)) test->success = TRUE; else return FALSE; input = g_io_stream_get_input_stream (G_IO_STREAM(connection)); if (g_input_stream_read (input, buffer, BUFFER_SIZE, NULL, &error) > 0) return TRUE; else return FALSE; } static void teardown (Test *test) { g_assert_true (g_socket_service_is_active (test->service)); g_thread_join (test->pam_test); g_socket_service_stop (test->service); g_assert_false (g_socket_service_is_active (test->service)); g_object_unref (test->address); g_unlink (test->control_path); g_free (test->control_path); g_free (test); g_rmdir (dir_path); g_printf ("Teardown completed\n"); } static void * pam_auth_tests (gpointer data) { Test *test = data; enum pamtest_err ret; g_printf ("Executing PAM auth tests\n"); const char *auth_tokens[] = { "password", NULL }; struct pamtest_conv_data conv_data = { .in_echo_off = auth_tokens }; struct pam_testcase tests[] = { pam_test (PAMTEST_AUTHENTICATE, PAM_SUCCESS) }; g_assert_true (g_socket_service_is_active (test->service)); ret = run_pamtest (SERVICE, g_get_user_name (), &conv_data, tests, NULL); g_assert_cmpint (ret, ==, PAMTEST_ERR_OK); return NULL; } static void mock_service (void) { GError *error = NULL; Test *test; g_printf ("Starting mock service\n"); test = g_malloc (sizeof (Test)); test->success = FALSE; g_mkdtemp (dir_path); g_setenv ("GNOME_KEYRING_CONTROL", dir_path, TRUE); test->control_path = g_strconcat (dir_path, "/control", NULL); test->address = g_unix_socket_address_new (test->control_path); test->service = g_socket_service_new (); g_socket_service_stop (test->service); g_assert_false (g_socket_service_is_active (test->service)); g_signal_connect (test->service, "incoming", G_CALLBACK (is_bytes_exchanged), test); g_socket_listener_add_address (G_SOCKET_LISTENER (test->service), test->address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, NULL, NULL, &error); g_assert_no_error (error); g_socket_service_start (test->service); g_assert_true (g_socket_service_is_active (test->service)); test->pam_test = g_thread_new ("pam_test", pam_auth_tests, test); do g_main_context_iteration (NULL, TRUE); while (!test->success); teardown (test); } int main(int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/pam/test_pam_authtok", mock_service); return g_test_run(); } 0707010000009F000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000001400000000libsecret-0.21.7/po070701000000A0000081A400000000000000000000000167D9F0D90000010B000000000000000000000000000000000000001C00000000libsecret-0.21.7/po/LINGUAS# Please keep this list sorted alphabetically # ab an ar as be bg bs ca ca@valencia ckb cs da de el en_GB eo es eu fa fi fr fur gl he hi hr hu id ie it ja ka kab kk ko lt lv ml ms nb ne nl oc pa pl pt pt_BR ro ru sk sl sr sr@latin sv ta tg tr uk vi zh_CN zh_HK zh_TW 070701000000A1000081A400000000000000000000000167D9F0D900000061000000000000000000000000000000000000002000000000libsecret-0.21.7/po/POTFILES.inlibsecret/secret-item.c libsecret/secret-methods.c libsecret/secret-session.c tool/secret-tool.c 070701000000A2000081A400000000000000000000000167D9F0D900000905000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ab.po# Abkhazian translation for libsecret. # Copyright (C) 2022 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-02-02 12:24+0000\n" "PO-Revision-Date: 2022-02-02 12:24+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: Abkhazian \n" "Language: ab\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: libsecret/secret-item.c:1098 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Ииашам имаӡоу ацыԥха аҵәахырҭа аҟынтә аиура" #: libsecret/secret-methods.c:1056 msgid "Default keyring" msgstr "ацаԥхақәа реидҳәала ишыҟоу еиԥш" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Имаӡоу ацаԥхақәа рҵәахырҭа аҽамадара залымшахеит" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "ҿыц еиқәырхоу аҵакы азы адырга" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "Аизга, зыҩныҵҟа еиқәырхоу аҵакы зҭаӡо" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "Аԥшааразы шәхы иашәырхәаша ҩ-еилкаарак рҵакы" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr " ҩ-еилкаарак, зҵакы ианыххо ирышьашәалоу" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "Аизга, зҟаны ишьақәырӷәӷәатәу" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "Актәи амацара аҟәымҟәа,алҵшәақәа зегьы раарԥшра" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "Иаҭаххозар, алҵшәақәа рҵакқәа роужьра" 070701000000A3000081A400000000000000000000000167D9F0D90000084A000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/an.po# Aragonese translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=libsecret&keywords=I18N+L10N&component=general\n" "POT-Creation-Date: 2013-09-18 02:55+0000\n" "PO-Revision-Date: 2013-09-18 17:48+0100\n" "Last-Translator: Daniel Martinez \n" "Language-Team: Aragonese \n" "Language: an\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.4\n" #: ../libsecret/secret-item.c:1164 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Se recibió un secreto no valido de l'almagazenamiento de secretos" #: ../libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Depósito de claus predeterminau" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "No se podió comunicar con l'almacén de secretos" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "a etiqueta ta o nuevo elemento almagazenau" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "a colección en a quala colocar l'elemento almagazenau" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "pares atributo-valor de l'elemento que buscar" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "pares atributo-valor que coinciden con os elementos que limpiar" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "devolver totz os resultaus, en cuenta de solament o primer" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "desbloquiar elementos d'os resultaus si ye necesario" 070701000000A4000081A400000000000000000000000167D9F0D90000095D000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ar.po# Arabic translation for libsecret. # Copyright (C) 2014 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # # Mosaab Alzoubi , 2014. # Safa Alfulaij , 2014. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=libsecret&keywords=I18N+L10N&component=general\n" "POT-Creation-Date: 2014-09-30 10:00+0000\n" "PO-Revision-Date: 2014-10-06 09:19+0100\n" "Last-Translator: Safa Alfulaij \n" "Language-Team: Arabic \n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" "X-Generator: Lokalize 1.5\n" #: ../libsecret/secret-item.c:1161 #, c-format msgid "Received invalid secret from the secret storage" msgstr "استُقبِلَ سرّ غير سليم من مخزن الأسرار" #: ../libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "حلقة المفاتيح الافتراضية" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "تعذّر الاتّصال بمخزن الأسرار" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "عنوان العنصر المخزّن الجديد" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "التّشكيل المُعدّ لشَغْل مكان العنصر المخزّن" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "أزواج قيم الصفات للبحث عنها" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "أزواج قيم الصفات المطابقة للعناصر لمحوها" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "أعد كل النّتائج، بدلًا من الأولى فقط" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "ألغِ قفل عنصر النّتائج في حال الضّرورة" 070701000000A5000081A400000000000000000000000167D9F0D900000A45000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/as.po# Assamese translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # # Nilamdyuti Goswami , 2013. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=libsecret&keywords=I18N+L10N&component=general\n" "POT-Creation-Date: 2013-09-12 17:52+0000\n" "PO-Revision-Date: 2013-09-13 18:35+0530\n" "Last-Translator: Nilamdyuti Goswami \n" "Language-Team: Assamese \n" "Language: as\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Lokalize 1.5\n" #: ../libsecret/secret-item.c:1164 #, c-format msgid "Received invalid secret from the secret storage" msgstr "গোপন সংৰক্ষণৰ পৰা অবৈধ গোপন তথ্য প্ৰাপ্ত হৈছে" #: ../libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "অবিকল্পিত কিৰিং" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "গোপন সংৰক্ষণৰ সৈতে সংযোগ কৰিব পৰা নগল" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "নতুন সংৰক্ষিত বস্তুৰ বাবে লেবেল" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "সংৰক্ষিত বস্তু থবলৈ সংগ্ৰহ" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "চাবলৈ বস্তুৰ বৈশিষ্ট্য মান যোৰ" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "পৰিষ্কাৰ কৰিব লগিয়া বস্তুবোৰৰ সৈতে মিল খোৱা বৈশিষ্ট্য মান যোৰ" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "সকলো ফলাফল দেখুৱাওক, কেৱল প্ৰথমটো দেখুৱাৰ পৰিৱৰ্তে" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "প্ৰয়োজন সাপেক্ষে বস্তুৰ ফলাফলসমূহ আনলক কৰিব" 070701000000A6000081A400000000000000000000000167D9F0D900000A32000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/be.pomsgid "" msgstr "" "Project-Id-Version: ab10e6d45488175674299c2d7fc854f6\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-08-27 09:56\n" "Last-Translator: Ihar Hrachyshka \n" "Language-Team: Belarusian\n" "Language: be\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || n%10>=5 && n%10<=9 || n%100>=11 && n%100<=14 ? 2 : 3);\n" "X-Crowdin-Project: ab10e6d45488175674299c2d7fc854f6\n" "X-Crowdin-Project-ID: 104\n" "X-Crowdin-Language: be\n" "X-Crowdin-File: /Localizations/Gnome/Development/libsecret.master.be.po\n" "X-Crowdin-File-ID: 3080\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Атрыманы хібны сакрэт з сакрэтнага сховішча" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Прадвызначаная вязка ключоў" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Не атрымалася звязацца з сакрэтным сховішчам" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "назва для новага элемента" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "калекцыя, у якой патрэбна размясціць элемент, які будзе захоўвацца" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "пары значэнняў атрыбутаў элемента для пошуку" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "пары значэнняў атрыбутаў адпаведных элементаў для ачысткі" #: tool/secret-tool.c:67 #| msgid "the collection in which to place the stored item" msgid "collection in which to lock" msgstr "калекцыя, у якой трэба заблакаваць" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "выдаць усе вынікі, а не толькі першы" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "калі патрэбна, разблакаваць вынікі" 070701000000A7000081A400000000000000000000000167D9F0D900000950000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/bg.po# Bulgarian translation of libsecret po-file. # Copyright (C) 2017 Free Software Foundation, Inc. # Copyright (C) 2022 Alexander Shopov. # This file is distributed under the same license as the libsecret package. # Alexander Shopov , 2017, 2022. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-02-22 00:31+0000\n" "PO-Revision-Date: 2022-03-21 14:02+0100\n" "Last-Translator: Alexander Shopov \n" "Language-Team: Bulgarian \n" "Language: bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: libsecret/secret-item.c:1106 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Получена е невалидна тайна от хранилището за тайни" #: libsecret/secret-methods.c:1060 msgid "Default keyring" msgstr "Стандартен ключодържател" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Няма връзка с хранилището за тайни" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "етикетът за новосъхраненият обект" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "къде да се запази този обект" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "двойки атрибут-стойност на търсения обект" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "двойки атрибут-стойност, които ще бъдат изтрити" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "колекция, в която да се заключва" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "всички резултати, а не само първия" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "отключване на обектите при необходимост" 070701000000A8000081A400000000000000000000000167D9F0D900000833000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/bs.po# Bosnian translation for bosnianuniversetranslation # Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 # This file is distributed under the same license as the bosnianuniversetranslation package. # FIRST AUTHOR , 2013. # msgid "" msgstr "" "Project-Id-Version: bosnianuniversetranslation\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=libsecret&keywords=I18N+L10N&component=general\n" "POT-Creation-Date: 2015-02-26 23:06+0000\n" "PO-Revision-Date: 2013-10-15 23:10+0000\n" "Last-Translator: Samir Ribić \n" "Language-Team: Bosnian \n" "Language: bs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2014-10-23 07:14+0000\n" "X-Generator: Launchpad (build 17203)\n" #: ../libsecret/secret-item.c:1161 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Primljena pogrešna tajna s tajne memorije" #: ../libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Podrazumijevani prsten ključeva" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "Ne mogu komunicirati s tajnom memorijom" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "labela za novosnimljenu stavku" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "kolekcija gdje će se smjestiti stavka" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "parovi atributa stavke koja se traži" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "parovi atributa stavki kojoji se podudaraju s onim za brisanje" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "vrati sve rezultate umjesto samo prvog" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "otključaj rezultat objekta ako je potrebno" 070701000000A9000081A400000000000000000000000167D9F0D90000084B000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ca.po# Catalan translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Gil Forcada , 2013. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/" "issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-10-30 17:02+0200\n" "Last-Translator: maite guix \n" "Language-Team: Catalan \n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "S'ha rebut un secret no vàlid del magatzem de secrets" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Clauer per defecte" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "No s'ha pogut contactar amb el magatzem de secrets" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "l'etiqueta per l'element desat nou" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "la col·lecció on s'ha de posar l'element desat" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "parells de valors d'atribut de l'element a cercar" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "" "parells de valors d'atribut que coincideixen amb els elements a " "esborrar" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "col·lecció en la qual blocar" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "retorna tots els resultats i no només el primer" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "desbloca els resultats de l'element si fa falta" 070701000000AA000081A400000000000000000000000167D9F0D900000859000000000000000000000000000000000000002300000000libsecret-0.21.7/po/ca@valencia.po# Catalan translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Gil Forcada , 2013. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" "product=libsecret&keywords=I18N+L10N&component=General\n" "POT-Creation-Date: 2017-07-18 14:03+0000\n" "PO-Revision-Date: 2013-08-31 22:12+0200\n" "Last-Translator: Xavi Ivars \n" "Language-Team: Catalan \n" "Language: ca-valencia\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bits\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: ../libsecret/secret-item.c:1165 #, c-format msgid "Received invalid secret from the secret storage" msgstr "S'ha rebut un secret no vàlid del magatzem de secrets" #: ../libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Anell de claus per defecte" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "No s'ha pogut contactar amb el magatzem de secrets" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "L'etiqueta per l'element guardat nou" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "la col·lecció on s'ha de posar l'element guardat" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "les parelles de valors d'atributs que es consulta de l'element" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "" "les parelles de valors d'atributs que es netegen dels elements que hi " "coincideixen" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "retorna tots els resultats i no només el primer" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "desbloca els resultats de l'element si fa falta" 070701000000AB000081A400000000000000000000000167D9F0D9000008C6000000000000000000000000000000000000001B00000000libsecret-0.21.7/po/ckb.po# Kurdish (Sorani) translation for libsecret # Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020 # This file is distributed under the same license as the libsecret package. # FIRST AUTHOR , 2020. # msgid "" msgstr "" "Project-Id-Version: libsecret\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2020-03-11 06:56+0100\n" "PO-Revision-Date: 2020-05-05 01:13+0300\n" "Language-Team: Kurdish (Sorani) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2020-05-04 22:12+0000\n" "X-Generator: Poedit 2.3\n" "Last-Translator: Jwtiyar Nariman \n" "Language: ckb\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "نهێنییەکی نادروست وەرگیرا لە بیرگە نهێنییەکە" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "مەدالیای بنەڕەتی" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "ناتوانرێ پەیوەندی بکرێ لەگەڵ بیرگە نهێنییەکە" #: tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "پێناسەکە بۆ بڕگە خەزنکراوە نوێییەکە" #: tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "کۆکراوەکە بۆ جێگای بڕگە خەزنکراوەکە" #: tool/secret-tool.c:43 tool/secret-tool.c:50 tool/secret-tool.c:443 msgid "attribute value pairs of item to lookup" msgstr "نرخی دوو دیارخراوی بڕگە بۆ گەڕان" #: tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "نرخی دوو دیارخراو کە لە ىرگەکان دەچێت بۆ پاککردنەوە" #: tool/secret-tool.c:439 msgid "return all results, instead of just first one" msgstr "هەموو ئانجامەکان دەگەڕێنەوە، لەجێی تەنها یەکەم دانە" #: tool/secret-tool.c:441 msgid "unlock item results if necessary" msgstr "ئەنجامەکانی بڕگەکە بکەرەوە ئەگەر پێویست بوو" 070701000000AC000081A400000000000000000000000167D9F0D900000878000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/cs.po# Czech translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Marek Černocký , 2013, 2021 # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-08-06 21:06+0200\n" "Last-Translator: Marek Černocký \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Gtranslator 2.91.6\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Přijata neplatná tajná informace z úložiště tajných dat" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Výchozí klíčenka" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Nelze komunikovat s úložištěm tajných dat" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "popisek pro nově ukládanou položku" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "kolekce, do které se má umístit ukládaná položka" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "dvojice atribut – hodnota hledané položky" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "dvojice atribut – hodnota, které odpovídají mazaným položkám" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "kolekce, ve které se má zamknout" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "vrátit všechny výsledky, ne jen první" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "odemknout položky výsledků, pokud je potřeba" 070701000000AD000081A400000000000000000000000167D9F0D900000844000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/da.po# Danish translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Kris Thomsen , 2013. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-08-28 11:56+0200\n" "Last-Translator: Alan Mortensen \n" "Language-Team: Danish \n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.3\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Modtog ugyldig hemmelighed fra det hemmelige lager" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Standardnøglering" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Kunne ikke kommunikere med det hemmelige lager" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "etiketten for det nye gemte element" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "samlingen, hvori det gemte element skal placeres" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "værdipar for attribut af elementer, som skal slås op" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "værdipar for attribut, som matcher elementer, som skal ryddes" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "samlingen, hvor der skal låses" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "returnér alle resultater, i stedet for kun det første" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "lås element resultater op, om nødvendigt" 070701000000AE000081A400000000000000000000000167D9F0D90000089F000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/de.po# German translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Tobias Endrigkeit , 2013. # Philipp Kiemle , 2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-08-17 14:32+0000\n" "PO-Revision-Date: 2021-09-14 20:05+0200\n" "Last-Translator: Tim Sabsch \n" "Language-Team: Deutsch \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Ungültiges Geheimnis aus dem Geheimspeicher erhalten" #: libsecret/secret-methods.c:1056 msgid "Default keyring" msgstr "Standard-Schlüsselbund" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Der Geheimspeicher konnte nicht erreicht werden" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "Die Bezeichnung für das neu gespeicherte Objekt" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "Die Sammlung, in welcher das gespeicherte Objekt abgelegt werden soll" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "Attribut-Wert-Paare des zu suchenden Objekts" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "Attribut-Wert-Paare, die auf das zu löschenden Objekt zutreffen" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "Sammlung, in der gesperrt werden soll" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "Alle Ergebnisse anstatt nur des ersten zurückgeben" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "Objektergebnisse bei Bedarf entsperren" 070701000000AF000081A400000000000000000000000167D9F0D900000AB5000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/el.po# Greek translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Dimitris Spingos , 2013. # Dimitris Spingos (Δημήτρης Σπίγγος) , 2013. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-07-26 08:24+0000\n" "PO-Revision-Date: 2023-09-09 02:21+0300\n" "Last-Translator: Efstathios Iosifidis \n" "Language-Team: team@lists.gnome.gr\n" "Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.3.2\n" "X-Project-Style: gnome\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Λήψη μη έγκυρου μυστικού από τη μυστική τοποθεσία αποθήκευσης" #: libsecret/secret-methods.c:1060 msgid "Default keyring" msgstr "Προεπιλεγμένη κλειδοθήκη" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Αδύνατη η επικοινωνία με τη μυστική τοποθεσία αποθήκευσης" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "η ετικέτα για το νεοαποθηκευμένο στοιχείο" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "η συλλογή στην οποία θα τοποθετηθεί το αποθηκευμένο στοιχείο" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "ιδιότητα ζευγών τιμών του στοιχείου προς αναζήτηση" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "ιδιότητα ζευγών τιμών που ταιριάζει με τα στοιχεία προς εκκαθάριση" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "συλλογή στην οποία να κλειδωθεί" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "επιστροφή όλων των αποτελεσμάτων, αντί να επιστρέφεται μόνο το πρώτο" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "ξεκλείδωμα των αποτελεσμάτων στοιχείου, αν απαιτείται" 070701000000B0000081A400000000000000000000000167D9F0D9000008A0000000000000000000000000000000000000001D00000000libsecret-0.21.7/po/en_GB.po# British English translation for libsecret. # Copyright (C) 2016 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Abigail Brady , Bastien Nocera , 2016. # Zander Brown , 2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-08-29 15:29+0100\n" "Last-Translator: Zander Brown \n" "Language-Team: English - United Kingdom \n" "Language: en_GB\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 40.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Received invalid secret from the secret storage" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Default keyring" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Couldn’t communicate with the secret storage" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "the label for the new stored item" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "the collection in which to place the stored item" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "attribute value pairs of item to lookup" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "attribute value pairs which match items to clear" #: tool/secret-tool.c:67 #| msgid "the collection in which to place the stored item" msgid "collection in which to lock" msgstr "collection in which to lock" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "return all results, instead of just first one" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "unlock item results if necessary" 070701000000B1000081A400000000000000000000000167D9F0D900000879000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/eo.po# Esperanto translation for libsecret. # Copyright (C) 2013 Free Software Foundation, Inc. # This file is distributed under the same license as the libsecret package. # Kristjan SCHMIDT , 2013-2023. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-07-26 08:24+0000\n" "PO-Revision-Date: 2023-09-27 22:05+0200\n" "Last-Translator: Kristjan SCHMIDT \n" "Language-Team: Esperanto \n" "Language: eo\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" "X-Generator: Gtranslator 42.0\n" "X-Project-Style: gnome\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Ricevis nevalidan sekreton de la sekret-konservejo" #: libsecret/secret-methods.c:1060 msgid "Default keyring" msgstr "Defaŭlta ŝlosilaro" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Ne eblis komuniki kun la sekret-konservejo" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "la etikedo por la nova konservita elemento" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "la kolekto en kiun meti la konservitan elementon" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "atribut-valor-paroj de la elserĉata elemento" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "atribut-valor-paroj kiuj kongruas al la forigendaj elementoj" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "kolekto en kiu ŝlosi" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "liveri ĉiujn rezultojn, anstataŭ nur la unuan" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "malŝlosi element-rezultojn se necesas" 070701000000B2000081A400000000000000000000000167D9F0D900000903000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/es.po# Spanish translation for libsecret. # Copyright (C) 2012 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # FIRST AUTHOR , YEAR. # Daniel Mustieles , 2012-2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-07-13 11:46+0200\n" "Last-Translator: Daniel Mustieles \n" "Language-Team: Spanish - Spain \n" "Language: es_ES\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 40.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Se recibió un secreto no válido del almacenamiento de secretos" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Depósito de claves predeterminado" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "No se pudo comunicar con almacén de secretos" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "la etiqueta para el nuevo elemento almacenado" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "la colección en la que colocar el elemento almacenado" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "pares atributo-valor del elemento que buscar" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "pares atributo-valor que coinciden con los elementos que limpiar" #: tool/secret-tool.c:67 #| msgid "the collection in which to place the stored item" msgid "collection in which to lock" msgstr "la colección en la que bloquear" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "devolver todos los resultados, en lugar de sólo el primero" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "desbloquear elementos de los resultados si es necesario" 070701000000B3000081A400000000000000000000000167D9F0D900000874000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/eu.po# Basque translation for libsecret. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Iñaki Larrañaga Murgoitio , 2014. # Asier Sarasua Garmendia , 021. # msgid "" msgstr "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-08-18 17:46+0200\n" "Last-Translator: Asier Sarasua Garmendia \n" "Language-Team: Basque \n" "Language: eu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Baliogabeko ezkutukoa jaso da ezkutuko biltegitik" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Gako-sorta lehenetsia" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Ezin izan da ezkutuko biltegiarekin komunikatu" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "etiketa (gordetako elementu berriarentzako)" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "bilduma (gordetako elementua kokatzeko)" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "bilaketako elementuaren atributu eta balio bikotea" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "garbituko diren elementuekin bat datozen atributu eta balio bikotea" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "blokeoa jasango duen bilduma" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "itzuli emaitza guztiak, aurrenekoa bakarrik itzuli ordez" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "desblokeatu emaitzako elementuak behar izanez gero" 070701000000B4000081A400000000000000000000000167D9F0D9000008FF000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/fa.po# Persian translation for libsecret. # Copyright (C) 2015 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Arash Mousavi , 2015. # Danial Behzadi , 2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-09-01 15:22+0430\n" "Last-Translator: Danial Behzadi \n" "Language-Team: Persian \n" "Language: fa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.2\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "رمز نامعتبر از مخزن رمز دریافت شد" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "دسته‌کلید پیش‌‌گزیده" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "نتوانست با مخزن رمز‌ ارتباط برقرار کند" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "برچسب مورد ذخیره شدهٔ جدید" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "مجموعهٔ قرار دادن مورد ذخیره شده" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "جفت مقدارهای ویژگی مورد برای جست‌وجو" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "جفت مقدارهای ویژگی برای پاک‌سازی موردهای منطبق" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "مجموعه‌‌ای که در آن قفل شود" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "برگرداندن تمام نتیجه‌ها، به جای تنها نخستین مورد" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "قفل‌گشایی نتیجه‌ها در صورت نیاز" 070701000000B5000081A400000000000000000000000167D9F0D900000804000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/fi.po# Finnish translation for libsecret. # Copyright (C) 2020 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # JRfi , 2020. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2020-07-23 09:25+0000\n" "PO-Revision-Date: 2020-08-07 22:08+0300\n" "Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Last-Translator: JR-Fi \n" "X-Generator: Poedit 2.0.6\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Vastaanotettiin epäkelpo salausavain salausavainten varastosta" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Oletus salausavainten kokoelma" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Ei pystynyt viestimään salausavainten varaston kanssa" #: tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "tunniste uudelle varastoidulle salausavaimelle" #: tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "salausavainten kokoelma, johon varastoitu asia kuuluu" #: tool/secret-tool.c:43 tool/secret-tool.c:50 tool/secret-tool.c:443 #, fuzzy msgid "attribute value pairs of item to lookup" msgstr "muuttujien ja niiden arvojen parit, joita etsitään" #: tool/secret-tool.c:57 #, fuzzy msgid "attribute value pairs which match items to clear" msgstr "muuttujien ja niiden arvojen parit, jotka täsmäävät" #: tool/secret-tool.c:439 msgid "return all results, instead of just first one" msgstr "palauttaa kaikki tulokset, ei vain ensimmäistä" #: tool/secret-tool.c:441 #, fuzzy msgid "unlock item results if necessary" msgstr "avaa kohteet, mikäli tarpeen" 070701000000B6000081A400000000000000000000000167D9F0D9000008F3000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/fr.po# French translation for libsecret. # Copyright (C) 2013 Listed translators # This file is distributed under the same license as the libsecret package. # Claude Paroz , 2013 # Charles Monzat , 2018. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-08-27 08:45+0200\n" "Last-Translator: Charles Monzat \n" "Language-Team: GNOME Frenech Team \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Gtranslator 3.30.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "" "Le stockage de données confidentielles a renvoyé des données non valides" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Trousseau de clés par défaut" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Impossible de communiquer avec le stockage de données confidentielles" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "l’étiquette du nouvel élément stocké" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "la collection dans laquelle placer l’élément stocké" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "paires de valeurs d’attributs de l’élément à rechercher" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "paires de valeurs d’attributs correspondant aux éléments à effacer" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "la collection dans laquelle verrouiller" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "renvoyer tous les résultats, non seulement le premier" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "déverrouiller si nécessaire les éléments obtenus" 070701000000B7000081A400000000000000000000000167D9F0D900000832000000000000000000000000000000000000001B00000000libsecret-0.21.7/po/fur.po# Friulian translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Fabio Tomat , 2013. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-07-26 18:09+0200\n" "Last-Translator: Fabio Tomat \n" "Language-Team: Friulian \n" "Language: fur\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Ricevût un segret no valit dal dispositîf di archiviazion dai segrets" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Puarteclâfs predefinît" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Impussibil comunicâ cul dispositîf di archiviazion dai segrets" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "le etichete par il gnûf element salvât" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "la colezion dulà plaçâ l'element salvât" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "pâr di valôrs dal atribût dal element di cirî" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "pâr di valôrs dal atribût che a corispuindin al atribût di eliminâ" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "la colezion dulà lâ a blocâ" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "torne ducj i risultâts invezit che dome il prin" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "sbloche i risultâts dai elements se necessari" 070701000000B8000081A400000000000000000000000167D9F0D900000990000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/gl.po# Galician translations for PACKAGE package. # Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Fran Diéguez , 2012. # Fran Dieguez , 2012-2021. # msgid "" msgstr "" "Project-Id-Version: libsecret mater\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-08-25 05:34+0000\n" "PO-Revision-Date: 2021-08-25 07:35+0200\n" "Last-Translator: Fran Dieguez \n" "Language-Team: Galician >\n" "Language: gl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" "X-Generator: Gtranslator 40.0\n" "X-DL-Team: gl\n" "X-DL-Module: libsecret\n" "X-DL-Branch: master\n" "X-DL-Domain: po\n" "X-DL-State: Translating\n" #: libsecret/secret-item.c:1104 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Recibiuse un segredo non válido desde o almacenamento de segredos" #: libsecret/secret-methods.c:1056 msgid "Default keyring" msgstr "Anel de chaves por omisión" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Non foi posíbel comunicarse co almacenamento de segredos" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "a etiqueta para o novo elemento almacenado" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "A colección na que se poñerá o elemento almacenado" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "pares de atributo-valor do elemento a buscar" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "pares de atributo-valor nos que os elementos a limpar deben coincidir" #: tool/secret-tool.c:67 #| msgid "the collection in which to place the stored item" msgid "collection in which to lock" msgstr "a colección na que se poñerá o elemento almacenado" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "devolver todos os resultados, no lugar de só un" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "desbloquear resultados do elemento se é preciso" 070701000000B9000081A400000000000000000000000167D9F0D90000085C000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/he.po# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Yaron Shahrabani , 2013. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-09-23 13:56+0300\n" "Last-Translator: Yaron Shahrabani \n" "Language-Team: Gezer\n" "Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "התקבל קוד שגוי מאחסון הסודות" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "קבוצת המפתחות כבררת המחדל" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "לא ניתן לתקשר עם מאגר הסודות" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "התווית לפריטים חדשים באחסון" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "האוסף בו לשים את הפריט המאוחסן" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "צמדי ערכי מאפיינים של פריט לחיפוש" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "צמדי ערכי מאפיינים של פריט לפינוי" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "האוסף בו לנעול" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "החזרת כל התוצאות במקום רק את הראשונה" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "שחרור תוצאות הפריטים אם נדרש" 070701000000BA000081A400000000000000000000000167D9F0D900000A71000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/hi.po# Hindi translation for libsecret. # Copyright (C) 2024 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Scrambled777 , 2024. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues/\n" "POT-Creation-Date: 2024-03-31 02:51+0000\n" "PO-Revision-Date: 2024-04-17 17:09+0530\n" "Last-Translator: Scrambled777 \n" "Language-Team: Hindi\n" "Language: hi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Gtranslator 46.0\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "गुप्त भंडार से अमान्य रहस्य प्राप्त हुआ" #: libsecret/secret-methods.c:1058 msgid "Default keyring" msgstr "डिफ़ॉल्ट कीरिंग" #: libsecret/secret-session.c:251 libsecret/secret-session.c:287 msgid "Couldn’t communicate with the secret storage" msgstr "गुप्त भंडारण के साथ संचार नहीं किया जा सका" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "नये संग्रहीत वस्तु के लिए लेबल" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "वह संग्रह जिसमें संग्रहित वस्तु को रखा जाए" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:462 msgid "attribute value pairs of item to lookup" msgstr "देखने के लिए वस्तु की विशेषता मान जोड़ी" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "विशेषता मान जोड़े जो साफ़ करने के लिए आइटम से मेल खाते हैं" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "संग्रह जिसमें बंद करना है" #: tool/secret-tool.c:458 msgid "return all results, instead of just first one" msgstr "केवल पहले परिणाम के बजाय सभी परिणाम लौटाएं" #: tool/secret-tool.c:460 msgid "unlock item results if necessary" msgstr "यदि जरूरी हो तो वस्तु परिणाम अनलॉक करें" 070701000000BB000081A400000000000000000000000167D9F0D900000858000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/hr.po# Croatian translation for libsecret. # Copyright (C) 2017 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-09-06 11:10+0200\n" "Last-Translator: gogo \n" "Language-Team: Croatian \n" "Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 2.3\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Primljena je neispravna tajna iz tajnog spremišta" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Zadani skup ključeva" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Nemoguća komunikacija s tajnim spremištem" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "naziv za novu spremljenu stavku" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "kolekcija u koju smjestiti spremljenu stavku" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "vrijednost svojstva para stavke za pretraživanje" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "vrijednost svojstva para koji se podudara sa stavkama za uklanjanje" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "kolekcija u koju zaključati" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "vrati sve rezultate, umjesto samo prvog" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "otključaj stavke rezultata ako je potrebno" 070701000000BC000081A400000000000000000000000167D9F0D900000877000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/hu.po# Hungarian translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # # Balázs Úr , 2013. # Balázs Úr , 2013. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-07-23 16:25+0200\n" "Last-Translator: Meskó Balázs \n" "Language-Team: Hungarian \n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Érvénytelen titok fogadva a titoktárból" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Alapértelmezett kulcstartó" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Nem lehet kommunikálni a titoktárral" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "az új tárolt elem címkéje" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "a gyűjtemény, amelybe a tárolt elem elhelyezésre került" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "a keresendő elem attribútum érték párjai" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "attribútum érték párok, amelyek illeszkednek a törlendő elemekre" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "a gyűjtemény, amelyben zárolni kell" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "minden eredmény visszaadása csak az első helyett" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "elem eredmények feloldása, ha szükséges" 070701000000BD000081A400000000000000000000000167D9F0D900000807000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/id.po# Indonesian translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Andika Triwidada , 2013. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-06-29 14:42+0700\n" "Last-Translator: Andika Triwidada \n" "Language-Team: Indonesian \n" "Language: id\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.3\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Menerima rahasia yang tak valid dari penyimpanan rahasia" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Ring kunci baku" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Tak bisa berkomunikasi dengan penyimpanan rahasia" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "label bagi butir yang baru disimpan" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "koleksi tempat tujuan butir yang disimpan" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "pasangan nilai atribut dari butir yang dicari" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "pasangan nilai atribut yang cocok dengan butir yang akan dibersihkan" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "koleksi tempat mengunci" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "mengembalikan semua hasil, bukan hanya yang pertama" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "buka kunci hasil butir bila perlu" 070701000000BE000081A400000000000000000000000167D9F0D900000781000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ie.po# Interlingue translation for libsecret. # Copyright (C) 2022 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Olga Smirnova , 2022. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-11-22 15:35+0000\n" "PO-Revision-Date: 2022-12-12 08:31+0700\n" "Language-Team: Interlingue \n" "Language: ie\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Last-Translator: OIS \n" "X-Generator: Poedit 1.8.12\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Un ínvalid secrete obtenet ex li magasine de secretes" #: libsecret/secret-methods.c:1060 msgid "Default keyring" msgstr "Porta-clave predefinit" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Ne successat communicar con li magasine de secretes" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "li etiquette del nov inmagasinat element" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "li collection a quel on deve metter li inmagasinat element" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "" #: tool/secret-tool.c:67 #, fuzzy msgid "collection in which to lock" msgstr "S_errar" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "retornar omni resultates in vice del prim" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "" 070701000000BF000081A400000000000000000000000167D9F0D900000894000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/it.po# Italian translations for libsecret # Copyright (C) 2013, 2021 the Free Software Foundation Inc. # This file is distributed under the same license as the libsecret package. # Milo Casagrande , 2013, 2021. # msgid "" msgstr "" "Project-Id-Version: libsecret\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-08-18 13:14+0200\n" "Last-Translator: Milo Casagrande \n" "Language-Team: Italian \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Poedit 2.4.2\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "" "Ricevuto un segreto non valido dal dispositivo di archiviazione dei segreti" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Portachiavi predefinito" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Impossibile comunicare col dispositivo di archiviazione dei segreti" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "l'etichetta per il nuovo elemento salvato" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "la collezione in cui posizionare l'elemento salvato" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "coppia di valori dell'attributo dell'elemento da cercare" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "" "coppia di valori dell'attributo corrispondenti all'attributo da eliminare" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "la collezione in cui bloccare" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "restituisce tutti i risultati invece che solamente il primo" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "sblocca gli oggetti dei risultati se necessario" 070701000000C0000081A400000000000000000000000167D9F0D900000671000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ja.po# libsecret ja.po. # Copyright (C) 2012 THE libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Takeshi AIHANA , 2012 # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-09-01 23:28+0900\n" "PO-Revision-Date: 2012-09-01 23:28+0900\n" "Last-Translator: Takeshi AIHANA \n" "Language-Team: Japanese \n" "Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../libsecret/secret-item.c:1164 #, c-format msgid "Received invalid secret from the secret storage" msgstr "シークレットのストレージから不正なシークレットを受け取りました" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:282 msgid "Couldn’t communicate with the secret storage" msgstr "シークレットのストレージと通信できませんでした" #: ../tool/secret-tool.c:37 msgid "the label for the new stored item" msgstr "新しいアイテムのラベルを指定する" #: ../tool/secret-tool.c:39 msgid "the collection in which to place the stored item" msgstr "アイテムを格納しておくコレクションを指定する" #: ../tool/secret-tool.c:41 ../tool/secret-tool.c:48 msgid "attribute value pairs of item to lookup" msgstr "検索するアイテムの属性値のペア" #: ../tool/secret-tool.c:55 msgid "attribute value pairs which match items to clear" msgstr "一致するものがあればクリアするアイテムの属性値のペア" 070701000000C1000081A400000000000000000000000167D9F0D900000B4A000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ka.po# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: libsecret\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-05-27 09:29+0000\n" "PO-Revision-Date: 2022-06-25 09:15+0200\n" "Last-Translator: Temuri Doghonadze \n" "Language-Team: Georgian <(nothing)>\n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.1\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "საცავიდან მიღებული საიდუმლო არასწორია" #: libsecret/secret-methods.c:1060 msgid "Default keyring" msgstr "ნაგულისხმები ბრელოკი" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "საიდუმლოებების საცავთან კავშირის პრობლემა" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "ახალი დამახსოვრებული ელემენტის ჭდე" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "კოლექცია, რომელშიც დამახსოვრებული ელემენტი გნებავთ მოათავსოთ" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "ელემენტის მოსაძებნად ელემენტის ატრიბუტების მნიშვნელობების წყვილები" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "გასასუფთავებელი ელემენტების ატრიბუტების მნიშვნელობების წყვილები" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "კოლექცია, რომელშიც უნდა ჩავკეტო" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "ერთის მაგიერ ყველა შედეგის დაბრუნება" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "საჭიროების შემთხვევაში ელემენტის შედეგის განბლოკვა" 070701000000C2000081A400000000000000000000000167D9F0D9000007E8000000000000000000000000000000000000001B00000000libsecret-0.21.7/po/kab.po# Kabyle translation for libsecret. # Copyright (C) 2024 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Rachida SACI , 2024. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues/\n" "POT-Creation-Date: 2024-03-21 06:29+0000\n" "PO-Revision-Date: 2024-03-30 10:54+0100\n" "Last-Translator: sa\n" "Language-Team: Kabyle \n" "Language: kab\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.4.2\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Yettwarmes tuffirt tarameɣtut seg uḥraz uffir" #: libsecret/secret-methods.c:1058 msgid "Default keyring" msgstr "Keyring amezwer" #: libsecret/secret-session.c:251 libsecret/secret-session.c:287 msgid "Couldn’t communicate with the secret storage" msgstr "Ur yezmir ara ad yemmeslay akked uḥraz uffir" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "tabzimt i uferdis amaynut i yettwaḥerzen" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "talkensit anida yella uferdis yettwaḥerzen" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:462 msgid "attribute value pairs of item to lookup" msgstr "iyugan n wazal n umyerr n uferdis iɣef ara yili unadi" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "iyugan n wazal n umyerr yemṣadan d yiferdisen ara yettwasefḍen" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "talkensit anida ttwasekkṛen" #: tool/secret-tool.c:458 msgid "return all results, instead of just first one" msgstr "yerra-d akk igmaḍ, deg wadeg n yiwen kan" #: tool/secret-tool.c:460 msgid "unlock item results if necessary" msgstr "kkes asekkeṛ i yigmaḍ n uferdis ma yella ilaq" 070701000000C3000081A400000000000000000000000167D9F0D900000932000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/kk.po# Kazakh translation for libsecret. # Copyright (C) 2014 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Baurzhan Muftakhidinov , 2014-2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-08-30 13:31+0500\n" "Last-Translator: Baurzhan Muftakhidinov \n" "Language-Team: Kazakh \n" "Language: kk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Құпия сақтаушыдан қате құпия кілті алынды" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Бастапқы кілттер бауы" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Құпия сақтаушымен байланысу мүмкін емес" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "жаңа сақталатын нәрсе үшін белгі" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "сақталатын нәрсені орналастыру үшін жинақ" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "іздеу үшін нәрсенің атрибуттар мәндерінің жұбы" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "тазарту үшін нәрселер атрибуттар мәндерінің жұбы" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "блоктау үшін жинақ" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "барлық нәтижелерді қайтару, тек біріншіні емес" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "керек болса, нәрсе нәтижелерін блоктаудан босату" 070701000000C4000081A400000000000000000000000167D9F0D9000007DE000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ko.po# Korean translation for libsecret. # This file is distributed under the same license as the libsecret package. # # Changwoo Ryu , 2013, 2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-09-03 22:39+0900\n" "Last-Translator: Changwoo Ryu \n" "Language-Team: GNOME Korea \n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "비밀 저장소에서 잘못된 비밀 정보를 받았습니다" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "기본 키 모음" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "비밀 저장 장치와 통신할 수 없습니다" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "새로 저장한 항목의 레이블" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "저장한 항목을 놓을 모음" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "찾아볼 항목의 속성 값의 쌍" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "지울 항목에 해당하는 속성 값의 쌍" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "내부에서 잠글 모음" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "첫 번째 결과가 아니라 모든 결과를 리턴합니다" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "필요하면 항목 결과의 잠금을 풉니다" 070701000000C5000081A400000000000000000000000167D9F0D9000008AB000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/lt.po# Lithuanian translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Aurimas Černius , 2013-2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-06-27 18:21+0300\n" "Last-Translator: Aurimas Černius \n" "Language-Team: Lietuvių \n" "Language: lt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" "%100<10 || n%100>=20) ? 1 : 2)\n" "X-Generator: Gtranslator 40.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Iš paslapčių saugyklos gauta netinkama paslaptis" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Numatytoji raktinė" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Nepavyksta komunikuoti su paslapčių saugykla" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "etiketė naujai įrašomam elementui" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "rinkinys, į kurį patalpinti įrašomą elementą" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "elemento atributų verčių poros paieškai" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "atributų verčių poros, kurios atitinka išvalomus elementus" #: tool/secret-tool.c:67 #| msgid "the collection in which to place the stored item" msgid "collection in which to lock" msgstr "rinkinys, į kuriame rakinti" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "grąžinti visus rezultatus, o ne vieną" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "jei reikia, atrakinti rezultatus" 070701000000C6000081A400000000000000000000000167D9F0D900000883000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/lv.po# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Rūdolfs Mazurs , 2013, 2021. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-10-25 19:34+0300\n" "Last-Translator: Rūdolfs Mazurs \n" "Language-Team: Latvian \n" "Language: lv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 :" " 2);\n" "X-Generator: Lokalize 21.08.1\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Saņemts nederīgs noslēpums no izvēlētās krātuves" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Noklusējuma atslēgu saišķis" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Neizdevās sazināties ar slepeno krātuvi" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "no jauna saglabāto vienumu etiķetes" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "kolekcija, kurā novietot saglabātos vienumus" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "kolekcija, kurā novietot saglabātos vienumus" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "atribūtu vērtību pāri, kas atbilst attīrāmajiem vienumiem" #: tool/secret-tool.c:67 #| msgid "the collection in which to place the stored item" msgid "collection in which to lock" msgstr "kolekcija, kuru bloķēt" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "atgriezt visus rezultātus, ne tikai pirmo" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "atbloķēt vienumu rezultātus, ja nepieciešams" 070701000000C7000081A400000000000000000000000167D9F0D900000036000000000000000000000000000000000000002000000000libsecret-0.21.7/po/meson.buildi18n.gettext(meson.project_name(), preset: 'glib' ) 070701000000C8000081A400000000000000000000000167D9F0D900000A94000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ml.po# Malayalam translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Anish Sheela , 2013. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=libsecret&keywords=I18N+L10N&component=general\n" "POT-Creation-Date: 2013-10-10 11:47+0000\n" "PO-Revision-Date: 2013-10-11 21:55+0530\n" "Last-Translator: Anish Sheela \n" "Language-Team: Swatantra Malayalam Computing \n" "Language: ml\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Virtaal 0.7.1\n" "X-Project-Style: gnome\n" #: ../libsecret/secret-item.c:1164 #, c-format msgid "Received invalid secret from the secret storage" msgstr "രഹസ്യ സംഭരണിയില്‍ നിന്ന് സാധുവല്ലാത്ത രഹസ്യം കിട്ടി" #: ../libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "സ്വതവേയുള്ള ചാവികൂട്ടം" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "രഹസ്യസംഭരണിയുമായി ബന്ധപെടാനാകുന്നില്ല" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "പുതിയതായി സംഭരിച്ച ഇനത്തിന്റെ ലേബല്‍" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "സംഭരിക്കേണ്ട ഇനം വെയ്ക്കേണ്ട ശേഖരം" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "നോക്കേണ്ട ഇനത്തിന്റെ ഗുണം - വില ജോടി" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "ചേര്‍ന്ന ഇനങ്ങള്‍ മാറ്റേണ്ട ഗുണം - വില ജോടി" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "ആദ്യത്തേതിന് പകരം എല്ലാ ഫലങ്ങളും നല്‍കുക" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "ഇനത്തിന്റെ ഫലങ്ങള്‍ ആവശ്യമെങ്കില്‍ തുറക്കുക" 070701000000C9000081A400000000000000000000000167D9F0D90000075F000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ms.po# Malay translation for libsecret. # Copyright (C) 2019 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # abuyop , 2019. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2019-10-15 08:36+0000\n" "PO-Revision-Date: 2019-12-22 17:01+0800\n" "Language-Team: Malay \n" "Language: ms\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Last-Translator: abuyop \n" "X-Generator: Poedit 2.0.6\n" #: libsecret/secret-item.c:1162 msgid "Received invalid secret from the secret storage" msgstr "Menerima rahsia tidak sah dari storan rahsia" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Gelang kunci lalai" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Tidak dapat berkomunikasi dengan storan rahsia" #: tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "label untuk item tersimpan baharu" #: tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "koleksi yang menyimpan item tersimpan" #: tool/secret-tool.c:43 tool/secret-tool.c:50 tool/secret-tool.c:443 msgid "attribute value pairs of item to lookup" msgstr "pasangan item bernilai atribut yang dicari" #: tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "pasangan nilai atribut yang sepadan dengan item yang dikosongkan" #: tool/secret-tool.c:439 msgid "return all results, instead of just first one" msgstr "kembalikan semua keputusan, selain dari yang pertama" #: tool/secret-tool.c:441 msgid "unlock item results if necessary" msgstr "nyahkunci keputusan item jika perlu" 070701000000CA000081A400000000000000000000000167D9F0D9000007A1000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/nb.po# Norwegian bokmål translation of libsecret. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Kjartan Maraas , 2013. # msgid "" msgstr "" "Project-Id-Version: libsecret 3.9.x\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-08-22 16:06+0200\n" "PO-Revision-Date: 2013-08-22 16:07+0200\n" "Last-Translator: Kjartan Maraas \n" "Language-Team: Norwegian bokmål \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../libsecret/secret-item.c:1164 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Mottok ugyldig hemmelighet fra hemmelig lager" #: ../libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Forvalgt nøkkelring" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "Kunne ikke kommunisere med hemmelig lager" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "etikett for den nye lagrede oppføringen" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "samling den lagrede oppføringen skal plasseres i" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "attributt-/verdipar for oppføringer som skal slås opp" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "attributt-/verdi-par som er lik oppføringer som skal tømmes" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "returner alle resultater i stedet for bare det første" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "lås opp oppføringsresultater hvis nødvendig" 070701000000CB000081A400000000000000000000000167D9F0D900000A2A000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ne.po# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: Gnome Nepali Translation Project\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-07-26 08:24+0000\n" "PO-Revision-Date: 2022-09-19 11:10+0545\n" "Last-Translator: Pawan Chitrakar \n" "Language-Team: Nepali Translation Team \n" "Language: ne_NP\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0.1\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "गुप्त स्टोर देखि अमान्य गोप्य प्राप्त" #: libsecret/secret-methods.c:1060 msgid "Default keyring" msgstr "पूर्वनिर्धारित keyring" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "गुप्त स्टोरसङ्ग कुराकानी गर्न सकेन" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "नयाँ भण्डार वस्तुको लागि लेबल" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "सङ्ग्रह जसमा भण्डार वस्तु सङ्कलन राखिने" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "खोजि गर्न वस्तुको विशेषता जोडी मान" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "खाली गर्न मेल भएको वस्तुको विशेषता जोडी मान" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "ताल्चा लगाउने सङ्कलन" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "पहिलो मात्र नभएर सबै परिणाम देखाउनुहोस्" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "वस्तु परिणाम आवश्यक भए अनलक गर्नुहोस्" 070701000000CC000081A400000000000000000000000167D9F0D900000872000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/nl.po# Dutch translation of libsecret # Copyright (C) YEAR THE libsecret COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Reinout van Schouwen , 2013. # Nathan Follens , 2021. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-08-31 14:42+0200\n" "Last-Translator: Nathan Follens \n" "Language-Team: Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Ongeldig geheim ontvangen uit de geheimenopslag" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Standaard sleutelbos" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Communicatie met de geheimenopslag mislukt" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "het label voor het nieuwe opgeslagen item" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "de verzameling waarin het opgeslagen item geplaatst zal worden" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "attribuut-waardeparen van op te zoeken item" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "attribuut-waardeparen die overeenkomen met te wissen items" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "verzameling waarin vergrendeld moet worden" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "alle resultaten teruggeven, in plaats van alleen de eerste" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "item-resultaten ontgrendelen indien nodig" 070701000000CD000081A400000000000000000000000167D9F0D9000008F1000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/oc.po# Occitan translation for libsecret. # Copyright (C) 2013 Listed translators # This file is distributed under the same license as the libsecret package. # Cédric Valmary , 2015. # Cédric Valmary (Tot en òc) , 2015. # Cédric Valmary (totenoc.eu) , 2016. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-11-20 18:35+0100\n" "Last-Translator: Quentin PAGÈS\n" "Language-Team: Tot En Òc\n" "Language: oc\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.0\n" "X-Project-Style: gnome\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "L'emmagazinatge de donadas confidencialas a renviat de donadas invalidas" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Trossèl de claus per defaut" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Impossible de comunicar amb l'emmagazinatge de donadas confidencialas" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "l'etiqueta del novèl element emmagazinat" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "la colleccion dins la quala cal plaçar l'element emmagazinat" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "paras de valors d'atributs de l'element de recercar" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "paras de valors d'atributs que correspondon als elements d'escafar" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "la colleccion dins la quala verrolhar" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "renviar totes los resultats, e non pas solament lo primièr" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "desverrolhar se necessari los elements obtenguts" 070701000000CE000081A400000000000000000000000167D9F0D900000A13000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/pa.po# Punjabi translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # # A S Alam , 2013, 2023. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-07-26 08:24+0000\n" "PO-Revision-Date: 2023-08-30 19:04-0700\n" "Last-Translator: A S Alam \n" "Language-Team: Punjabi \n" "Language: pa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Lokalize 23.04.3\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "ਗੁਪਤ ਸਟੋਰੇਜ਼ ਤੋਂ ਗਲਤ ਭੇਦ ਮਿਲਿਆ" #: libsecret/secret-methods.c:1060 msgid "Default keyring" msgstr "ਮੂਲ ਕੀਰਿੰਗ" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "ਗੁਪਤ ਸਟੋਰੇਜ਼ ਨਾਲ ਸੰਚਾਰ ਨਹੀਂ ਹੋ ਸਕਿਆ" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "ਨਵੀਂ ਸਟੋਰ ਕੀਤੀ ਆਈਟਮ ਲਈ ਲੇਬਲ" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "ਭੰਡਾਰ, ਜਿਸ ਵਿੱਚ ਸਟੋਰ ਕੀਤੀ ਆਈਟਮ ਨੂੰ ਰੱਖਣਾ ਹੈ" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "ਖੋਜਣ ਵਾਲੀ ਆਈਟਮ ਦਾ ਗੁਣ ਮੁੱਲ ਜੋੜਾ" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "ਗੁਣ ਮੁੱਲ ਜੋੜੇ, ਜੋ ਸਾਫ਼ ਕੀਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਆਈਟਮਾਂ ਨਾਲ ਮਿਲਦੇ ਹਨ" #: tool/secret-tool.c:67 #| msgid "the collection in which to place the stored item" msgid "collection in which to lock" msgstr "ਭੰਡਾਰ, ਜਿਸ ਵਿੱਚ ਲਾਕ ਕਰਨਾ ਹੈ" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "ਕੇਵਲ ਇੱਕ ਦੀ ਬਜਾਏ ਸਭ ਨਤੀਜੇ ਦਿਓ" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "ਜੇ ਲੋੜ ਹੋਵੇ ਤਾਂ ਆਈਟਮ ਨਤੀਜੇ ਅਣ-ਲਾਕ" 070701000000CF000081A400000000000000000000000167D9F0D900000898000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/pl.po# Polish translation for libsecret. # Copyright © 2012-2021 the libsecret authors. # This file is distributed under the same license as the libsecret package. # Piotr Drąg , 2012-2021. # Aviary.pl , 2012-2021. # msgid "" msgstr "" "Project-Id-Version: libsecret\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-06-27 11:00+0200\n" "Last-Translator: Piotr Drąg \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Otrzymano nieprawidłowy sekret z przechowalni" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Domyślna baza kluczy" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Nie można komunikować się z przechowalnią" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "etykieta dla nowo przechowywanego elementu" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "kolekcja, w której umieścić przechowywany element" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "pary wartości atrybutu wyszukiwanego elementu" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "pary wartości atrybutu pasujące do czyszczonych elementów" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "kolekcja, w której zablokować" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "zwraca wszystkie wyniki, zamiast tylko pierwszego" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "odblokowuje wyniki elementów, jeśli to potrzebne" 070701000000D0000081A400000000000000000000000167D9F0D9000008C9000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/pt.po# libsecret's Portuguese translation. # Copyright © 2013 libsecret # This file is distributed under the same license as the libsecret package. # Fernando Carvalho , 2013. # Pedro Albuquerque , 2015. # Hugo Carvalho , 2021. # msgid "" msgstr "" "Project-Id-Version: 3.10\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-06-25 18:24+0100\n" "Last-Translator: Hugo Carvalho \n" "Language-Team: Português \n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0\n" "X-Project-Style: gnome\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Recebido segredo inválido do armazenamento secreto" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Chaveiro predefinido" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Não foi possível comunicar com o armazenamento secreto" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "o rótulo para o novo item armazenado" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "a coleção onde colocar o item armazenado" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "pares de valores de atributos no item para procura" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "pares de valores de atributos que correspondem ao item para limpar" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "a coleção na qual bloquear" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "devolver todos os resultados, em vez de apenas o primeiro" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "desbloquear resultados de item se necessário" 070701000000D1000081A400000000000000000000000167D9F0D9000008B7000000000000000000000000000000000000001D00000000libsecret-0.21.7/po/pt_BR.po# Brazilian Portuguese translation for libsecret. # Copyright (C) 2021 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Rafael Ferreira , 2012, 2013. # Enrico Nicoletto , 2021. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-06-24 10:39-0300\n" "Last-Translator: Enrico Nicoletto \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 2.4.3\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Recebeu segredo inválido do armazenamento de segredos" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Chaveiro padrão" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Não foi possível comunicar com o armazenamento de segredos" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "o rótulo para o novo item armazenado" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "a coleção na qual será colocada o item armazenado" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "pares de valores de atributos de item para procurar" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "pares de valores de atributos que correspondem aos itens para apagar" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "coleção a qual será bloqueada" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "retorna todos os resultados, ao invés de apenas o primeiro" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "destrava resultados do item, se necessário" 070701000000D2000081A400000000000000000000000167D9F0D9000008F9000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ro.po# Romanian translation for libsecret. # Copyright (C) 2015 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Daniel Șerbănescu , 2015. # Daniel Șerbănescu , 2015. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-06-30 16:36+0200\n" "Last-Translator: Daniel Șerbănescu \n" "Language-Team: Gnome Romanian Translation Team\n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " "20)) ? 1 : 2);;\n" "X-Generator: Poedit 2.4.3\n" "X-Project-Style: gnome\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "S-a primit un secret nevalid de la depozitul de secrete" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Inel de chei implicit" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Nu s-a putut comunica cu depozitul de secrete" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "eticheta pentru noul element stocat" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "colecția în care să fie plasat noul element" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "perechi atribut-valoare ale elementelor de căutat" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "perechi atribut-valoare care se potrivesc elementelor de curățat" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "colecția în care să se blocheze" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "returnează toate rezultatele, în loc de doar primul" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "deblochează rezultatele elementelor dacă este necesar" 070701000000D3000081A400000000000000000000000167D9F0D9000009F4000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ru.po# Russian translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Stas Solovey , 2013. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-06-28 15:06+0300\n" "Last-Translator: Alexey Rubtsov \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Получен неверный секретный ключ из хранилища" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Связка ключей по умолчанию" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Не удалось связаться с хранилищем секретных ключей" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "метка для нового сохранённого значения" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "коллекция, в которую помещается сохранённое значение" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "значения пары атрибутов для поиска" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "значения пары атрибутов, соответствующие удаляемым" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "коллекция, в которой нужно зафиксировать" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "выводить все результаты, а не только первый" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "разблокировать результаты значений при необходимости" 070701000000D4000081A400000000000000000000000167D9F0D90000092E000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/sk.po# Slovak translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Pavol Klačanský , 2013. # Dušan Kazik , 2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-10-05 13:34+0200\n" "Last-Translator: Dušan Kazik \n" "Language-Team: Slovak \n" "Language: sk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0\n" "X-Generator: Gtranslator 40.0\n" # PK: toto je podivne #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Bolo prijaté tajomstvo z úložiska tajomstiev" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Predvolený zväzok kľúčov" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Nepodarilo sa komunikovať s úložiskom tajomstiev" # cmd desc #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "menovka pre novo uloženú položku" # cmd desc #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "zbierka, do ktorej sa zaradí uložená položka" # cmd desc #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "páry (atribút, hodnota) vyhľadávanej položky" # cmd desc #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "páry (atribút, hodnota) zodpovedajúci mazanej položke" # cmd desc #: tool/secret-tool.c:67 #| msgid "the collection in which to place the stored item" msgid "collection in which to lock" msgstr "zbierka, do ktorej sa má uzamknúť" # cmd desc #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "vráti všetky výsledky, nie len prvý" # cmd desc #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "odomknúť nájdené položky ak je to nevyhnutné" 070701000000D5000081A400000000000000000000000167D9F0D9000008E1000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/sl.po# Slovenian translation for libsecret. # Copyright (C) 2012 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # # Matej Urbančič , 2012–2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-30 14:38+0000\n" "PO-Revision-Date: 2021-06-30 18:09+0200\n" "Last-Translator: Matej Urbančič \n" "Language-Team: Slovenian GNOME Translation Team \n" "Language: sl_SI\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" "%100==4 ? 3 : 0);\n" "X-Poedit-SourceCharset: utf-8\n" "X-Generator: Poedit 2.4.2\n" #: libsecret/secret-item.c:1104 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Prejeto je neveljavno skrivno geslo za skrito mesto shranjevanja" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Privzeta zbirka ključev" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Ni mogoče vzpostaviti povezave s skritim mestom za shranjevanje" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "oznaka za na novo shranjen predmet" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "zbirka, v kateri naj bodo shranjeni predmeti" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "atribut para vrednosti predmeta za poizvedbo" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "atribut para vrednosti skladnih s predmeti za počiščenje" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "zbirka, v kateri naj bodo zaklenjeni predmeti" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "izpiši vse rezultate, ne le prvega" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "po potrebi odkleni rezultate predmeta" 070701000000D6000081A400000000000000000000000167D9F0D900000A1D000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/sr.po# Serbian translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Мирослав Николић , 2013. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-09-24 04:14+0200\n" "Last-Translator: Марко М. Костић \n" "Language-Team: Serbian \n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : n" "%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Project-Style: gnome\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Примљена је неисправна тајна из складишта тајни" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Основни привезак кључева" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Не могу да комуницирам са складиштем тајни" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "натпис за нову ускладиштену ставку" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "збирка у којој ће бити стављена ускладиштена ставка" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "парови вредности особина ставке за тражење" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "парови вредности особина који одговарају ставкама за чишћење" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "збирка у којој треба закључати" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "даје све резултате, уместо само првог" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "откључава резултате ставке ако је неопходно" 070701000000D7000081A400000000000000000000000167D9F0D900000896000000000000000000000000000000000000002000000000libsecret-0.21.7/po/sr@latin.po# Serbian translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Miroslav Nikolić , 2013. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=libsec" "ret&keywords=I18N+L10N&component=general\n" "POT-Creation-Date: 2013-02-18 14:22+0000\n" "PO-Revision-Date: 2013-02-20 20:24+0200\n" "Last-Translator: Miroslav Nikolić \n" "Language-Team: Serbian \n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : " "n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Project-Style: gnome\n" #: ../libsecret/secret-item.c:1164 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Primljena je neispravna tajna iz skladišta tajni" #: ../libsecret/secret-methods.c:1029 msgid "Default keyring" msgstr "Osnovni privezak ključeva" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "Ne mogu da komuniciram sa skladištem tajni" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "natpis za novu uskladištenu stavku" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "zbirka u kojoj će biti stavljena uskladištena stavka" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "parovi vrednosti osobina stavke za traženje" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "parovi vrednosti osobina koji odgovaraju stavkama za čišćenje" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "daje sve rezultate, umesto samo prvog" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "otključava rezultate stavke ako je neophodno" 070701000000D8000081A400000000000000000000000167D9F0D900000896000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/sv.po# Swedish translation for libsecret. # Copyright © 2014-2023 Free Software Foundation, Inc. # This file is distributed under the same license as the libsecret package. # Mattias Eriksson , 2014. # Anders Jonsson , 2021, 2023. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-07-26 08:24+0000\n" "PO-Revision-Date: 2023-08-17 14:04+0200\n" "Last-Translator: Anders Jonsson \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.3.2\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Mottog en ogiltig hemlighet från hemlighetsförrådet" #: libsecret/secret-methods.c:1060 msgid "Default keyring" msgstr "Standardnyckelring" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Kunde inte kommunicera med hemlighetsförrådet" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "etiketten för det nya lagrade objektet" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "samlingen i vilken det lagrade objektet ska placeras" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "attribut/värde-par av objekt att slå upp" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "attribut/värde-par vilka matchar objekt att rensa" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "samlingen i vilken låsning ska ske" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "returnera alla resultat, i stället för bara det första" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "lås upp objektresultat om nödvändigt" 070701000000D9000081A400000000000000000000000167D9F0D900000AB7000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/ta.po# Tamil translation for libsecret. # Copyright (C) 2021 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # ridhubharan , 2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues/\n" "POT-Creation-Date: 2024-01-06 08:10+0000\n" "PO-Revision-Date: 2024-01-09 07:10+0530\n" "Last-Translator: \n" "Language-Team: Tamil \n" "Language: ta\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Language: ta\n" "X-Source-Language: C\n" "X-Generator: Poedit 3.4\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "இரகசிய சேமிப்பிலிருந்து தவறான இரகசியம் பெறப்பட்டது" #: libsecret/secret-methods.c:1058 msgid "Default keyring" msgstr "இயல்புநிலை விசை வளையம்" #: libsecret/secret-session.c:251 libsecret/secret-session.c:287 msgid "Couldn’t communicate with the secret storage" msgstr "இரகசிய சேமிப்பகத்துடன் தொடர்பு கொள்ள முடியவில்லை" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "புதிய சேமிக்கப்பட்ட உருப்படிக்கான சிட்டை" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "சேமிக்கப்பட்ட உருப்படியை வைக்க வேண்டிய தொகுப்பு" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:462 msgid "attribute value pairs of item to lookup" msgstr "தேடப்படவேண்டிய உருப்படியின் மதிப்பு இணைகள்" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "பூட்டப்படவேண்டிய வேண்டிய தொகுப்பு" #: tool/secret-tool.c:458 msgid "return all results, instead of just first one" msgstr "முதல் முடிவுக்கு பதிலாக எல்லா முடிவுகளையும் தரவும்" #: tool/secret-tool.c:460 msgid "unlock item results if necessary" msgstr "தேவைப்பட்டால் உருப்படி முடிவுகளைத் திறக்கவும்" 070701000000DA000081A400000000000000000000000167D9F0D900000952000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/tg.po# Tajik translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Victor Ibragimov , 2013. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=libsecret&keywords=I18N+L10N&component=general\n" "POT-Creation-Date: 2013-10-09 18:03+0000\n" "PO-Revision-Date: 2013-10-10 16:44+0500\n" "Last-Translator: Victor Ibragimov \n" "Language-Team: Tajik \n" "Language: tg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.7\n" #: ../libsecret/secret-item.c:1164 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Асрори нодуруст аз захирагоҳи асрорҳо қабул шудааст" #: ../libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Ҳалқаи калидҳои пешфарз" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "Бо захирагоҳи асрорҳо пайваст нашуд" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "Барчасп барои объекти захирашудаи нав" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "Коллексия барои ҷойгир кардани объекти захирашуда" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "Ҷуфтҳои қимати сифати объект барои ҷустуҷӯ" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "Ҷуфтҳои қимати сифати объекти мувофиқ барои пок кардан" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "Намоиш додани ҳамаи натиҷаҳо, ба ғайр аз натиҷаи аввалин" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "Кушодани натиҷаҳои объект, агар лозим бошад" 070701000000DB000081A400000000000000000000000167D9F0D9000008E4000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/tr.po# Turkish translation for libsecret # Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 # Copyright (C) 2013-2023 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # # Muhammet Kara , 2014. # Burhan Keleş , 2021. # Emin Tufan Çetin , 2021. # msgid "" msgstr "" "Project-Id-Version: libsecret\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2022-09-18 07:57+0000\n" "PO-Revision-Date: 2021-09-19 20:05+0300\n" "Last-Translator: Emin Tufan Çetin \n" "Language-Team: Türkçe \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2014-05-30 21:52+0000\n" "X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=1; plural=0;\n" #: libsecret/secret-item.c:1130 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Giz deposudan geçersiz bir giz alındı" #: libsecret/secret-methods.c:1060 msgid "Default keyring" msgstr "Öntanımlı anahtarlık" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Giz deposu ile haberleşilemedi" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "saklanacak yeni ögenin etiketi" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "saklanan ögenin yerleştirileceği koleksiyon" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "aranacak ögenin öznitelik değer çiftleri" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "temizlenecek ögelerle eşleşen öznitelik değer çiftleri" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "kilitlenecek koleksiyon" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "yalnızca ilki yerine tüm sonuçları döndür" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "gerektiğinde öge sonuçlarının kilidini aç" 070701000000DC000081A400000000000000000000000167D9F0D900000A46000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/uk.po# Ukrainian translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Daniel Korostil , 2013. # Yuri Chornoivan , 2021. msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-06-24 15:03+0300\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Lokalize 20.12.0\n" "X-Project-Style: gnome\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "Одержано неправильний таємний ключ зі сховища" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "Типова в'язка ключів" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Не вдалося зв'язатися зі сховищем таємних ключів" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "мітка для новозбереженого об'єкта" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "збірка, в яку поміщається збережений об'єкт" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "значення пари атрибутів об'єкта для пошуку" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "значення пари атрибутів, що збігаються з об'єктами для очищення" #: tool/secret-tool.c:67 #| msgid "the collection in which to place the stored item" msgid "collection in which to lock" msgstr "збірка для блокування" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "виводити усі результати, а не лише перший" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "розблоковувати результати об'єктів за потреби" 070701000000DD000081A400000000000000000000000167D9F0D9000008C9000000000000000000000000000000000000001A00000000libsecret-0.21.7/po/vi.po# Vietnamese translation for libsecret. # Copyright (C) 2021 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # Trần Ngọc Quân , 2021. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-09-24 02:15+0000\n" "PO-Revision-Date: 2021-09-25 09:03+0700\n" "Last-Translator: Trần Ngọc Quân \n" "Language-Team: Vietnamese \n" "Language: vi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Gtranslator 3.38.0\n" #: libsecret/secret-item.c:1104 #, c-format msgid "Received invalid secret from the secret storage" msgstr "Đã nhận được khóa bí mật không hợp lệ từ kho chứa khóa bí mật" #: libsecret/secret-methods.c:1056 msgid "Default keyring" msgstr "Chùm chìa khóa mặc định" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "Không thể kết nối với kho chứa khóa bí mật" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "nhãn cho mục được lưu mới" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "bộ sưu tập để đặt mục được lưu trữ" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "các cặp giá trị thuộc tính của mục để tra cứu" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "các cặp giá trị thuộc tính khớp với mục để xóa" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "bộ sưu tập để khóa" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "trả về tất cả các kết quả, thay vì chỉ cái đầu tiên" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "mở khóa các kết quả mục tin nếu cần thiết" 070701000000DE000081A400000000000000000000000167D9F0D9000007A2000000000000000000000000000000000000001D00000000libsecret-0.21.7/po/zh_CN.po# Chinese (China) translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # eternalhui , 2013. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-09-17 14:07-0400\n" "Language-Team: Chinese (China) \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Last-Translator: Boyuan Yang <073plan@gmail.com>\n" "X-Generator: Poedit 3.0\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "从秘密存储区收到无效的秘密" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "默认密钥环" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "无法连接到秘密存储区" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "新存储项目的标签" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "用来存放存储项目的集合" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "用于查询项目的属性值对" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "用于匹配后清除项目的属性值对" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "要锁定的集合" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "返回所有结果,而不是仅仅第一个" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "如有必要,解锁项目结果" 070701000000DF000081A400000000000000000000000167D9F0D900000758000000000000000000000000000000000000001D00000000libsecret-0.21.7/po/zh_HK.po# Chinese (Hong Kong) translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-07-20 20:07+0800\n" "PO-Revision-Date: 2013-07-20 20:07+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: Chinese (Hong Kong) \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.5\n" #: ../libsecret/secret-item.c:1164 #, c-format msgid "Received invalid secret from the secret storage" msgstr "從機密儲存區收到無效的機密" #: ../libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "預設密碼匙圈" #: ../libsecret/secret-session.c:244 ../libsecret/secret-session.c:281 msgid "Couldn’t communicate with the secret storage" msgstr "無法與機密儲存區連線" #: ../tool/secret-tool.c:39 msgid "the label for the new stored item" msgstr "新儲存項目的標籤" #: ../tool/secret-tool.c:41 msgid "the collection in which to place the stored item" msgstr "用來放置儲存項目的收藏" #: ../tool/secret-tool.c:43 ../tool/secret-tool.c:50 ../tool/secret-tool.c:437 msgid "attribute value pairs of item to lookup" msgstr "要尋找的項目屬性數值配對" #: ../tool/secret-tool.c:57 msgid "attribute value pairs which match items to clear" msgstr "符合要清除項目的屬性數值配對" #: ../tool/secret-tool.c:433 msgid "return all results, instead of just first one" msgstr "傳回所有結果,而不僅只有第一項" #: ../tool/secret-tool.c:435 msgid "unlock item results if necessary" msgstr "如果需要則解鎖項目結果" 070701000000E0000081A400000000000000000000000167D9F0D9000007B1000000000000000000000000000000000000001D00000000libsecret-0.21.7/po/zh_TW.po# Chinese (Taiwan) translation for libsecret. # Copyright (C) 2013 libsecret's COPYRIGHT HOLDER # This file is distributed under the same license as the libsecret package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: libsecret master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/libsecret/issues\n" "POT-Creation-Date: 2021-06-24 11:59+0000\n" "PO-Revision-Date: 2021-07-10 17:43+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: Chinese (Taiwan) \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.2\n" #: libsecret/secret-item.c:1104 msgid "Received invalid secret from the secret storage" msgstr "從機密儲存區收到無效的機密" #: libsecret/secret-methods.c:1055 msgid "Default keyring" msgstr "預設鑰匙圈" #: libsecret/secret-session.c:243 libsecret/secret-session.c:279 msgid "Couldn’t communicate with the secret storage" msgstr "無法與機密儲存區連線" #: tool/secret-tool.c:42 msgid "the label for the new stored item" msgstr "新儲存項目的標籤" #: tool/secret-tool.c:44 msgid "the collection in which to place the stored item" msgstr "用來放置儲存項目的收藏" #: tool/secret-tool.c:46 tool/secret-tool.c:53 tool/secret-tool.c:458 msgid "attribute value pairs of item to lookup" msgstr "要尋找的項目屬性數值配對" #: tool/secret-tool.c:60 msgid "attribute value pairs which match items to clear" msgstr "符合要清除項目的屬性數值配對" #: tool/secret-tool.c:67 msgid "collection in which to lock" msgstr "用來鎖定的收藏" #: tool/secret-tool.c:454 msgid "return all results, instead of just first one" msgstr "傳回所有結果,而不僅只有第一項" #: tool/secret-tool.c:456 msgid "unlock item results if necessary" msgstr "如果需要則解鎖項目結果" 070701000000E1000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000001D00000000libsecret-0.21.7/subprojects070701000000E2000081A400000000000000000000000167D9F0D90000009E000000000000000000000000000000000000002C00000000libsecret-0.21.7/subprojects/gi-docgen.wrap[wrap-git] directory=gi-docgen url=https://gitlab.gnome.org/GNOME/gi-docgen.git push-url=ssh://git@gitlab.gnome.org:GNOME/gi-docgen.git revision=main depth=1 070701000000E3000041ED00000000000000000000000267D9F0D900000000000000000000000000000000000000000000001600000000libsecret-0.21.7/tool070701000000E4000081A400000000000000000000000167D9F0D900000234000000000000000000000000000000000000002200000000libsecret-0.21.7/tool/meson.buildsecret_tool_sources = [ 'secret-tool.c', ] secret_tool = executable('secret-tool', secret_tool_sources, dependencies: libsecret_dep, include_directories: config_h_dir, c_args: libsecret_cflags, install: true, ) if with_crypto and host_machine.system() != 'windows' test('test-secret-tool.sh', find_program('test-secret-tool.sh'), env: test_env, suite: 'secret-tool', ) endif if get_option('tpm2') test('test-secret-tool-tpm2.sh', find_program('test-secret-tool-tpm2.sh'), env: test_env, suite: 'secret-tool', ) endif 070701000000E5000081A400000000000000000000000167D9F0D900003D49000000000000000000000000000000000000002400000000libsecret-0.21.7/tool/secret-tool.c/* libsecret - GLib wrapper for Secret Service * * Copyright 2012 Red Hat Inc. * * 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 licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Author: Stef Walter */ #include "config.h" #include "libsecret/secret-item.h" #include "libsecret/secret-password.h" #include "libsecret/secret-retrievable.h" #include "libsecret/secret-value.h" #include "libsecret/secret-service.h" #include "libsecret/secret-paths.h" #include #include #include #include #include #include #define SECRET_ALIAS_PREFIX "/org/freedesktop/secrets/aliases/" #define SECRET_COLLECTION_PREFIX "/org/freedesktop/secrets/collection/" static gchar **attribute_args = NULL; static gchar *store_label = NULL; static gchar *store_collection = NULL; /* secret-tool store --label="blah" --collection="xxxx" name:xxxx name:yyyy */ static const GOptionEntry STORE_OPTIONS[] = { { "label", 'l', 0, G_OPTION_ARG_STRING, &store_label, N_("the label for the new stored item"), NULL }, { "collection", 'c', 0, G_OPTION_ARG_STRING, &store_collection, N_("the collection in which to place the stored item"), NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &attribute_args, N_("attribute value pairs of item to lookup"), NULL }, { NULL } }; /* secret-tool lookup name:xxxx yyyy:zzzz */ static const GOptionEntry LOOKUP_OPTIONS[] = { { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &attribute_args, N_("attribute value pairs of item to lookup"), NULL }, { NULL } }; /* secret-tool clear name:xxxx yyyy:zzzz */ static const GOptionEntry CLEAR_OPTIONS[] = { { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &attribute_args, N_("attribute value pairs which match items to clear"), NULL }, { NULL } }; /* secret-tool lock collections="xxxx" */ static const GOptionEntry COLLECTION_OPTIONS[] = { { "collection", 'c', 0, G_OPTION_ARG_STRING, &store_collection, N_("collection in which to lock"), NULL }, { NULL } }; typedef int (* SecretToolAction) (int argc, char *argv[]); static void usage (void) G_GNUC_NORETURN; static void usage (void) { g_printerr ("usage: secret-tool store --label='label' attribute value ...\n"); g_printerr (" secret-tool lookup attribute value ...\n"); g_printerr (" secret-tool clear attribute value ...\n"); g_printerr (" secret-tool search [--all] [--unlock] attribute value ...\n"); g_printerr (" secret-tool lock --collection='collection'\n"); exit (2); } static gboolean is_password_value (SecretValue *value) { const gchar *content_type; const gchar *data; gsize length; content_type = secret_value_get_content_type (value); if (content_type && g_str_equal (content_type, "text/plain")) return TRUE; data = secret_value_get (value, &length); /* gnome-keyring-daemon used to return passwords like this, so support this, but validate */ if (!content_type || g_str_equal (content_type, "application/octet-stream")) return g_utf8_validate (data, length, NULL); return FALSE; } static GHashTable * attributes_from_arguments (gchar **args) { GHashTable *attributes; if (args == NULL || args[0] == NULL) { g_printerr ("%s: must specify attribute and value pairs\n", g_get_prgname ()); usage (); } attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); while (args[0] != NULL) { if (args[1] == NULL) { g_printerr ("%s: must specify attributes and values in pairs\n", g_get_prgname ()); usage (); } g_hash_table_insert (attributes, g_strdup (args[0]), g_strdup (args[1])); args += 2; } return attributes; } static int secret_tool_action_clear (int argc, char *argv[]) { GError *error = NULL; GOptionContext *context; GHashTable *attributes; gboolean ret; context = g_option_context_new ("attribute value ..."); g_option_context_add_main_entries (context, CLEAR_OPTIONS, GETTEXT_PACKAGE); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("%s\n", error->message); usage(); } g_option_context_free (context); attributes = attributes_from_arguments (attribute_args); g_strfreev (attribute_args); ret = secret_password_clearv_sync (NULL, attributes, NULL, &error); g_hash_table_unref (attributes); if (!ret) { if (error != NULL) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); g_error_free (error); } return 1; } return 0; } static void write_password_data (SecretValue *value) { const gchar *at; gsize length; int r; at = secret_value_get (value, &length); while (length > 0) { r = write (1, at, length); if (r == -1) { if (errno != EAGAIN && errno != EINTR) { g_printerr ("%s: couldn't write password: %s\n", g_get_prgname (), g_strerror (errno)); exit (1); } } else { at += r; length -= r; } } } static void write_password_stdout (SecretValue *value) { if (!is_password_value (value)) { g_printerr ("%s: secret does not contain a textual password\n", g_get_prgname ()); exit (1); } write_password_data (value); /* Add a new line if we're writing out to a tty */ if (isatty (1)) write (1, "\n", 1); } static int secret_tool_action_lookup (int argc, char *argv[]) { GError *error = NULL; GOptionContext *context; GHashTable *attributes; SecretValue *value = NULL; context = g_option_context_new ("attribute value ..."); g_option_context_add_main_entries (context, LOOKUP_OPTIONS, GETTEXT_PACKAGE); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("%s\n", error->message); usage(); } g_option_context_free (context); attributes = attributes_from_arguments (attribute_args); g_strfreev (attribute_args); value = secret_password_lookupv_binary_sync (NULL, attributes, NULL, &error); g_hash_table_unref (attributes); if (error != NULL) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); g_error_free (error); return 1; } if (value == NULL) return 1; write_password_stdout (value); secret_value_unref (value); return 0; } static SecretValue * read_password_stdin (void) { gchar *password; gchar *at; gsize length = 0; gsize remaining = 8192; int r; at = password = g_malloc0 (remaining + 1); for (;;) { r = read (0, at, remaining); if (r == 0) { break; } else if (r < 0) { if (errno != EAGAIN && errno != EINTR) { g_printerr ("%s: couldn't read password: %s\n", g_get_prgname (), g_strerror (errno)); exit (1); } } else { /* TODO: This restriction is due purely to laziness. */ if (r == remaining) g_printerr ("%s: password is too long\n", g_get_prgname ()); at += r; remaining -= r; length += r; } } if (g_utf8_validate (password, -1, NULL)) { return secret_value_new_full (password, length, "text/plain", (GDestroyNotify)secret_password_free); } else { g_printerr ("%s: password not valid UTF-8\n", g_get_prgname ()); exit (1); } } static SecretValue * read_password_tty (void) { gchar *password; password = getpass ("Password: "); return secret_value_new_full (password, -1, "text/plain", (GDestroyNotify)secret_password_wipe); } static int secret_tool_action_store (int argc, char *argv[]) { GError *error = NULL; GOptionContext *context; GHashTable *attributes; SecretValue *value; gchar *collection = NULL; gboolean ret; context = g_option_context_new ("attribute value ..."); g_option_context_add_main_entries (context, STORE_OPTIONS, GETTEXT_PACKAGE); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("%s\n", error->message); usage(); } g_option_context_free (context); if (store_label == NULL) { g_printerr ("%s: must specify a label for the new item\n", g_get_prgname ()); usage (); } attributes = attributes_from_arguments (attribute_args); g_strfreev (attribute_args); if (store_collection) { /* TODO: Verify that the collection is a valid path or path element */ if (g_str_has_prefix (store_collection, "/")) collection = g_strdup (store_collection); else collection = g_strconcat (SECRET_ALIAS_PREFIX, store_collection, NULL); } if (isatty (0)) value = read_password_tty (); else value = read_password_stdin (); ret = secret_password_storev_binary_sync (NULL, attributes, collection, store_label, value, NULL, &error); secret_value_unref (value); g_hash_table_unref (attributes); g_free (store_label); g_free (store_collection); g_free (collection); if (!ret) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); return 1; } return 0; } static void print_item_when (const char *field, guint64 when) { GDateTime *dt; gchar *value; if (!when) { value = g_strdup (""); } else { dt = g_date_time_new_from_unix_utc (when); value = g_date_time_format (dt, "%Y-%m-%d %H:%M:%S"); g_date_time_unref (dt); } g_print ("%s = %s\n", field, value); g_free (value); } static void on_retrieve_secret (GObject *source_object, GAsyncResult *res, gpointer user_data) { SecretRetrievable *item = SECRET_RETRIEVABLE (source_object); GMainLoop *loop = user_data; SecretValue *secret; GHashTableIter iter; GHashTable *attributes; const gchar *value, *key; guint64 when; gchar *label; const gchar *part; const gchar *path; GError *error; error = NULL; secret = secret_retrievable_retrieve_secret_finish (item, res, &error); if (!secret) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); g_clear_error (&error); } if (G_IS_DBUS_PROXY (item)) { path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)); g_return_if_fail (path != NULL); /* The item identifier */ part = strrchr (path, '/'); if (part == NULL) part = path; g_print ("[%s]\n", part); } else { g_print ("[no path]\n"); } /* The label */ label = secret_retrievable_get_label (item); g_print ("label = %s\n", label); g_free (label); if (secret) { /* The secret value */ g_print ("secret = "); if (secret != NULL) { write_password_data (secret); secret_value_unref (secret); } g_print ("\n"); } /* The dates */ when = secret_retrievable_get_created (item); print_item_when ("created", when); when = secret_retrievable_get_modified (item); print_item_when ("modified", when); /* The attributes */ attributes = secret_retrievable_get_attributes (item); value = g_hash_table_lookup (attributes, "xdg:schema"); if (value) g_print ("schema = %s\n", value); g_hash_table_iter_init (&iter, attributes); while (g_hash_table_iter_next (&iter, (void **)&key, (void **)&value)) { if (strcmp (key, "xdg:schema") != 0) g_printerr ("attribute.%s = %s\n", key, value); } g_hash_table_unref (attributes); g_main_loop_quit (loop); } static int secret_tool_action_search (int argc, char *argv[]) { GError *error = NULL; GOptionContext *context; GHashTable *attributes; SecretSearchFlags flags; gboolean flag_all = FALSE; gboolean flag_unlock = FALSE; GList *items, *l; /* secret-tool lookup name xxxx yyyy zzzz */ const GOptionEntry lookup_options[] = { { "all", 'a', 0, G_OPTION_ARG_NONE, &flag_all, N_("return all results, instead of just first one"), NULL }, { "unlock", 'a', 0, G_OPTION_ARG_NONE, &flag_unlock, N_("unlock item results if necessary"), NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &attribute_args, N_("attribute value pairs of item to lookup"), NULL }, { NULL } }; context = g_option_context_new ("attribute value ..."); g_option_context_add_main_entries (context, lookup_options, GETTEXT_PACKAGE); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("%s\n", error->message); usage(); } g_option_context_free (context); attributes = attributes_from_arguments (attribute_args); g_strfreev (attribute_args); flags = SECRET_SEARCH_LOAD_SECRETS; if (flag_all) flags |= SECRET_SEARCH_ALL; if (flag_unlock) flags |= SECRET_SEARCH_UNLOCK; items = secret_password_searchv_sync (NULL, attributes, flags, NULL, &error); if (error == NULL) { GMainLoop *loop = g_main_loop_new (NULL, FALSE); for (l = items; l != NULL; l = g_list_next (l)) { SecretRetrievable *retrievable = SECRET_RETRIEVABLE (l->data); secret_retrievable_retrieve_secret (retrievable, NULL, on_retrieve_secret, loop); g_main_loop_run (loop); } g_list_free_full (items, g_object_unref); g_main_loop_unref (loop); } g_hash_table_unref (attributes); if (error != NULL) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); g_error_free (error); return 1; } return 0; } static int secret_tool_action_lock (int argc, char *argv[]) { int ret = 0; SecretService *service = NULL; GError *error = NULL; GOptionContext *context = NULL; GList *locked = NULL; GList *collections = NULL; SecretCollection *collection = NULL; service = secret_service_get_sync (SECRET_SERVICE_LOAD_COLLECTIONS, NULL, &error); if (error != NULL) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); ret = 1; goto out; } context = g_option_context_new ("collections"); g_option_context_add_main_entries (context, COLLECTION_OPTIONS, GETTEXT_PACKAGE); g_option_context_parse (context, &argc, &argv, &error); if (store_collection != NULL) { char *collection_path = NULL; collection_path = g_strconcat (SECRET_COLLECTION_PREFIX, store_collection, NULL); collection = secret_collection_new_for_dbus_path_sync (service, collection_path, SECRET_COLLECTION_NONE, NULL, &error); g_free (store_collection); g_free (collection_path); if (error != NULL) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); ret = 1; goto out; } if (secret_collection_get_locked (collection) || collection == NULL) { ret = 1; goto out; } collections = g_list_append (collections, g_steal_pointer (&collection)); } else { collections = secret_service_get_collections (service); } secret_service_lock_sync (NULL, collections, 0, &locked, &error); if (error != NULL) { g_printerr ("%s: %s\n", g_get_prgname (), error->message); ret = 1; goto out; } out: g_clear_object (&collection); g_clear_list (&collections, g_object_unref); g_clear_list (&locked, g_object_unref); g_clear_pointer (&context, g_option_context_free); g_clear_error (&error); g_clear_object (&service); return ret; } int main (int argc, char *argv[]) { SecretToolAction action; setlocale (LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #endif if (argc < 2) usage(); if (g_str_equal (argv[1], "store")) { action = secret_tool_action_store; } else if (g_str_equal (argv[1], "lookup")) { action = secret_tool_action_lookup; } else if (g_str_equal (argv[1], "clear")) { action = secret_tool_action_clear; } else if (g_str_equal (argv[1], "search")) { action = secret_tool_action_search; } else if (g_str_equal (argv[1], "lock")) { action = secret_tool_action_lock; } else { usage (); } argv[1] = argv[0]; return (action) (argc - 1, argv + 1); } 070701000000E6000081ED00000000000000000000000167D9F0D9000007CC000000000000000000000000000000000000002F00000000libsecret-0.21.7/tool/test-secret-tool-tpm2.sh#!/bin/sh set -e testdir=$PWD/test-secret-tool-tpm2-$$ test -d "$testdir" || mkdir "$testdir" cleanup () { rm -rf "$testdir" } trap cleanup 0 cd "$testdir" SECRET_BACKEND=file export SECRET_BACKEND SECRET_FILE_TEST_PATH=$testdir/keyring export SECRET_FILE_TEST_PATH : ${SECRET_TOOL="$abs_top_builddir"/tool/secret-tool} : ${DIFF=diff} echo 1..6 echo test1 | ${SECRET_TOOL} store --label label1 foo bar if test $? -eq 0; then echo "ok 1 /secret-tool/store1" else echo "not ok 1 /secret-tool/store1" fi echo test2 | ${SECRET_TOOL} store --label label2 foo bar apple orange if test $? -eq 0; then echo "ok 2 /secret-tool/store2" else echo "not ok 2 /secret-tool/store2" fi echo test1 > lookup.exp ${SECRET_TOOL} lookup foo bar > lookup.out if ${DIFF} lookup.exp lookup.out > lookup.diff; then echo "ok 3 /secret-tool/lookup" else echo "not ok 3 /secret-tool/lookup" sed 's/^/# /' lookup.diff exit 1 fi cat > search.exp < search.out if test $? -ne 0; then echo "not ok 4 /secret-tool/search" exit 1 fi if ${DIFF} search.exp search.out > search.diff; then echo "ok 4 /secret-tool/search" else echo "not ok 4 /secret-tool/search" sed 's/^/# /' search.diff exit 1 fi ${SECRET_TOOL} clear apple orange if test $? -eq 0; then echo "ok 5 /secret-tool/clear" else echo "not ok 5 /secret-tool/clear" exit 1 fi cat > search-after-clear.exp < search-after-clear.out if test $? -ne 0; then echo "not ok 6 /secret-tool/search-after-clear" exit 1 fi if ${DIFF} search-after-clear.exp search-after-clear.out > search-after-clear.diff; then echo "ok 6 /secret-tool/search-after-clear" else echo "not ok 6 /secret-tool/search-after-clear" sed 's/^/# /' search-after-clear.diff exit 1 fi 070701000000E7000081ED00000000000000000000000167D9F0D90000080C000000000000000000000000000000000000002A00000000libsecret-0.21.7/tool/test-secret-tool.sh#!/bin/sh set -e testdir=$PWD/test-secret-tool-$$ test -d "$testdir" || mkdir "$testdir" cleanup () { rm -rf "$testdir" } trap cleanup 0 cd "$testdir" SECRET_BACKEND=file export SECRET_BACKEND SECRET_FILE_TEST_PATH=$testdir/keyring export SECRET_FILE_TEST_PATH SECRET_FILE_TEST_PASSWORD=test export SECRET_FILE_TEST_PASSWORD : ${SECRET_TOOL="$abs_top_builddir"/tool/secret-tool} : ${DIFF=diff} echo 1..6 echo test1 | ${SECRET_TOOL} store --label label1 foo bar if test $? -eq 0; then echo "ok 1 /secret-tool/store1" else echo "not ok 1 /secret-tool/store1" fi echo test2 | ${SECRET_TOOL} store --label label2 foo bar apple orange if test $? -eq 0; then echo "ok 2 /secret-tool/store2" else echo "not ok 2 /secret-tool/store2" fi echo test1 > lookup.exp ${SECRET_TOOL} lookup foo bar > lookup.out if ${DIFF} lookup.exp lookup.out > lookup.diff; then echo "ok 3 /secret-tool/lookup" else echo "not ok 3 /secret-tool/lookup" sed 's/^/# /' lookup.diff exit 1 fi cat > search.exp < search.out if test $? -ne 0; then echo "not ok 4 /secret-tool/search" exit 1 fi if ${DIFF} search.exp search.out > search.diff; then echo "ok 4 /secret-tool/search" else echo "not ok 4 /secret-tool/search" sed 's/^/# /' search.diff exit 1 fi ${SECRET_TOOL} clear apple orange if test $? -eq 0; then echo "ok 5 /secret-tool/clear" else echo "not ok 5 /secret-tool/clear" exit 1 fi cat > search-after-clear.exp < search-after-clear.out if test $? -ne 0; then echo "not ok 6 /secret-tool/search-after-clear" exit 1 fi if ${DIFF} search-after-clear.exp search-after-clear.out > search-after-clear.diff; then echo "ok 6 /secret-tool/search-after-clear" else echo "not ok 6 /secret-tool/search-after-clear" sed 's/^/# /' search-after-clear.diff exit 1 fi 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!3856 blocks