├── pam_kwallet_init ├── .kde-ci.yml ├── .gitlab-ci.yml ├── plasma-kwallet-pam.service.in ├── .gitignore ├── pam_darwin.h ├── README.txt ├── pam_darwin.c ├── LICENSES ├── BSD-3-Clause.txt ├── CC0-1.0.txt └── LGPL-2.1-or-later.txt ├── cmake └── modules │ └── FindPAM.cmake ├── CMakeLists.txt ├── pam_kwallet_init.desktop.cmake └── pam_kwallet.c /pam_kwallet_init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if test -n "$PAM_KWALLET5_LOGIN" ; then 4 | env | socat STDIN UNIX-CONNECT:$PAM_KWALLET5_LOGIN 5 | fi 6 | 7 | -------------------------------------------------------------------------------- /.kde-ci.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: None 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | Dependencies: 5 | - 'on': ['@all'] 6 | 'require': 7 | 'frameworks/extra-cmake-modules': '@latest-kf6' 8 | 'frameworks/kwallet': '@latest-kf6' 9 | Options: 10 | require-passing-tests-on: ['Linux', 'FreeBSD'] 11 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: None 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | include: 5 | - project: sysadmin/ci-utilities 6 | file: 7 | - /gitlab-templates/linux-qt6.yml 8 | - /gitlab-templates/freebsd-qt6.yml 9 | - /gitlab-templates/xml-lint.yml 10 | - /gitlab-templates/yaml-lint.yml 11 | - /gitlab-templates/linux-qt6-next.yml 12 | -------------------------------------------------------------------------------- /plasma-kwallet-pam.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Unlock kwallet from pam credentials 3 | PartOf=graphical-session.target 4 | Before=plasma-plasmashell.service plasma-kded6.service 5 | After=plasma-kwin_wayland.service plasma-kcminit.service 6 | 7 | [Service] 8 | ExecStart=@CMAKE_INSTALL_FULL_LIBEXECDIR@/pam_kwallet_init 9 | Type=simple 10 | Slice=background.slice 11 | Restart=no 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore the following files 2 | .vscode 3 | *~ 4 | *.[oa] 5 | *.diff 6 | *.kate-swp 7 | *.kdev4 8 | .kdev_include_paths 9 | *.kdevelop.pcs 10 | *.moc 11 | *.moc.cpp 12 | *.orig 13 | *.user 14 | .*.swp 15 | .swp.* 16 | Doxyfile 17 | Makefile 18 | avail 19 | random_seed 20 | /build*/ 21 | CMakeLists.txt.user* 22 | .clang-format 23 | /compile_commands.json 24 | .clangd 25 | .idea 26 | /cmake-build* 27 | .cache 28 | -------------------------------------------------------------------------------- /pam_darwin.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2015 Samuel Gaist 11 | 12 | void pam_vsyslog(const pam_handle_t *ph, int priority, const char *fmt, va_list args); 13 | void pam_syslog(const pam_handle_t *ph, int priority, const char *fmt, ...); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | How kwallet-pam works: 2 | 3 | During the pam "auth" (pam_authenticate) stage the module gets the password in plain text. 4 | It hashes it against a random salt previously generated by kwallet of random data and keeps it in memory. 5 | 6 | When we get to the "session" (pam_open_session) stage the pam module forks and launches kwalletd as the user with file descriptor AND a socket. 7 | We send the salted password over the file descriptor after forking and write the socket address to an env variable. 8 | 9 | KWalletd recieves the pre-hashed key and then sits there doing nothing. (before the QApplication constructor) 10 | 11 | Later after session startup (autostart apps phase 0) a small script passes the newly set environment from the user session to kwalletd over the socket. 12 | 13 | kwalletd receives this, sets the environment variables and continues into the normal bootup. 14 | 15 | The session env is needed as if we launch pre session various important env vars are not set and kwalletd is a graphical app. 16 | 17 | -------------------------------------------------------------------------------- /pam_darwin.c: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2015 Samuel Gaist 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | void pam_vsyslog(const pam_handle_t *ph, int priority, const char *fmt, va_list args) 17 | { 18 | char *msg = NULL; 19 | const char *service = NULL; 20 | int retval; 21 | 22 | retval = pam_get_item(ph, PAM_SERVICE, (const void **) &service); 23 | if (retval != PAM_SUCCESS) 24 | service = NULL; 25 | if (vasprintf(&msg, fmt, args) < 0) { 26 | syslog(LOG_CRIT | LOG_AUTHPRIV, "cannot allocate memory in vasprintf: %m"); 27 | return; 28 | } 29 | syslog(priority | LOG_AUTHPRIV, "%s%s%s: %s", 30 | (service == NULL) ? "" : "(", 31 | (service == NULL) ? "" : service, 32 | (service == NULL) ? "" : ")", msg); 33 | free(msg); 34 | } 35 | 36 | void pam_syslog(const pam_handle_t *ph, int priority, const char *fmt, ...) 37 | { 38 | va_list args; 39 | 40 | va_start(args, fmt); 41 | pam_vsyslog(ph, priority, fmt, args); 42 | va_end(args); 43 | } 44 | -------------------------------------------------------------------------------- /LICENSES/BSD-3-Clause.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) . All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 26 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /cmake/modules/FindPAM.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the PAM libraries 2 | # Once done this will define 3 | # 4 | # PAM_FOUND - system has pam 5 | # PAM_INCLUDE_DIR - the pam include directory 6 | # PAM_LIBRARIES - libpam library 7 | # 8 | # SPDX-License-Identifier: BSD-3-Clause 9 | 10 | if (PAM_INCLUDE_DIR AND PAM_LIBRARY) 11 | # Already in cache, be silent 12 | set(PAM_FIND_QUIETLY TRUE) 13 | endif (PAM_INCLUDE_DIR AND PAM_LIBRARY) 14 | 15 | find_path(PAM_INCLUDE_DIR NAMES security/pam_appl.h pam/pam_appl.h) 16 | find_library(PAM_LIBRARY pam) 17 | find_library(DL_LIBRARY dl) 18 | 19 | if (PAM_INCLUDE_DIR AND PAM_LIBRARY) 20 | set(PAM_FOUND TRUE) 21 | if (DL_LIBRARY) 22 | set(PAM_LIBRARIES ${PAM_LIBRARY} ${DL_LIBRARY}) 23 | else (DL_LIBRARY) 24 | set(PAM_LIBRARIES ${PAM_LIBRARY}) 25 | endif (DL_LIBRARY) 26 | 27 | if (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h) 28 | # darwin claims to be something special 29 | set(HAVE_PAM_PAM_APPL_H 1) 30 | endif (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h) 31 | 32 | if (NOT DEFINED PAM_MESSAGE_CONST) 33 | include(CheckCXXSourceCompiles) 34 | # XXX does this work with plain c? 35 | check_cxx_source_compiles(" 36 | #if ${HAVE_PAM_PAM_APPL_H}+0 37 | # include 38 | #else 39 | # include 40 | #endif 41 | 42 | static int PAM_conv( 43 | int num_msg, 44 | const struct pam_message **msg, /* this is the culprit */ 45 | struct pam_response **resp, 46 | void *ctx) 47 | { 48 | return 0; 49 | } 50 | 51 | int main(void) 52 | { 53 | struct pam_conv PAM_conversation = { 54 | &PAM_conv, /* this bombs out if the above does not match */ 55 | 0 56 | }; 57 | 58 | return 0; 59 | } 60 | " PAM_MESSAGE_CONST) 61 | endif (NOT DEFINED PAM_MESSAGE_CONST) 62 | set(PAM_MESSAGE_CONST ${PAM_MESSAGE_CONST} CACHE BOOL "PAM expects a conversation function with const pam_message") 63 | 64 | endif (PAM_INCLUDE_DIR AND PAM_LIBRARY) 65 | 66 | if (PAM_FOUND) 67 | if (NOT PAM_FIND_QUIETLY) 68 | message(STATUS "Found PAM: ${PAM_LIBRARIES}") 69 | endif (NOT PAM_FIND_QUIETLY) 70 | else (PAM_FOUND) 71 | if (PAM_FIND_REQUIRED) 72 | message(FATAL_ERROR "PAM was not found") 73 | endif(PAM_FIND_REQUIRED) 74 | endif (PAM_FOUND) 75 | 76 | mark_as_advanced(PAM_INCLUDE_DIR PAM_LIBRARY DL_LIBRARY PAM_MESSAGE_CONST) 77 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(pam_kwallet) 3 | set(KF6_MIN_VERSION "6.18.0") 4 | set(KDE_COMPILERSETTINGS_LEVEL "5.82") 5 | set(PROJECT_VERSION "6.5.80") 6 | 7 | set(CMAKE_CXX_STANDARD 20) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | 10 | find_package (ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE) 11 | set (CMAKE_MODULE_PATH ${ECM_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) 12 | 13 | include(CheckFunctionExists) 14 | include(KDEInstallDirs) 15 | include(KDEClangFormat) 16 | include(ECMConfiguredInstall) 17 | include(KDEGitCommitHooks) 18 | include(ECMDeprecationSettings) 19 | 20 | find_package(PAM REQUIRED) 21 | find_package(PkgConfig REQUIRED) 22 | pkg_check_modules(LIBGCRYPT REQUIRED IMPORTED_TARGET libgcrypt) 23 | 24 | find_program(SOCAT_EXECUTABLE socat) 25 | 26 | if (SOCAT_EXECUTABLE) 27 | message (STATUS "Found socat executable: ${SOCAT_EXECUTABLE}") 28 | else () 29 | message (WARNING "socat is required for pam_kwallet to work") 30 | endif () 31 | 32 | include_directories ( 33 | ${PAM_INCLUDE_DIR} 34 | ${CMAKE_BINARY_DIR} 35 | ${CMAKE_CURRENT_BINARY_DIR} 36 | ) 37 | 38 | ecm_set_disabled_deprecation_versions(QT 6.9.0 39 | KF 6.16.0 40 | ) 41 | 42 | set(library_name "pam_kwallet5") 43 | 44 | set(pam_kwallet_SRCS 45 | pam_kwallet.c 46 | ) 47 | 48 | if (NOT KWALLETD_BIN_PATH) 49 | message (STATUS "KWALLETD_BIN_PATH not set, trying KF6::Wallet") 50 | find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS 51 | Wallet 52 | ) 53 | endif () 54 | 55 | add_definitions(-DKWALLETD_BIN_PATH="${KWALLETD_BIN_PATH}") 56 | 57 | if (APPLE) 58 | LIST(APPEND pam_kwallet_SRCS 59 | pam_darwin.c 60 | ) 61 | endif() 62 | 63 | # Handle different PAM header styles: 64 | # - "Linux style" has pam_ext.h 65 | # - "BSD style" has pam_appl.h 66 | # 67 | find_file(PAM_EXT_PATH security/pam_ext.h) 68 | find_file(PAM_APPL_PATH security/pam_appl.h) 69 | if (PAM_EXT_PATH) 70 | add_definitions(-DHAVE_PAM_EXT) 71 | endif() 72 | if (PAM_APPL_PATH) 73 | add_definitions(-DHAVE_PAM_APPL) 74 | endif() 75 | 76 | set(CMAKE_REQUIRED_INCLUDES "string.h") 77 | check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO) 78 | set(CMAKE_REQUIRED_INCLUDES) 79 | 80 | if (HAVE_EXPLICIT_BZERO) 81 | add_definitions(-DHAVE_EXPLICIT_BZERO) 82 | endif() 83 | 84 | add_library (${library_name} SHARED ${pam_kwallet_SRCS}) 85 | set_target_properties (${library_name} PROPERTIES PREFIX "") 86 | target_link_libraries (${library_name} 87 | ${PAM_LIBRARIES} 88 | PkgConfig::LIBGCRYPT 89 | ) 90 | 91 | # add clang-format target for all our real source files 92 | file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h) 93 | kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES}) 94 | 95 | kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT) 96 | 97 | install(TARGETS ${library_name} DESTINATION ${KDE_INSTALL_LIBDIR}/security) 98 | 99 | configure_file(pam_kwallet_init.desktop.cmake ${CMAKE_BINARY_DIR}/pam_kwallet_init.desktop) 100 | 101 | install(PROGRAMS pam_kwallet_init DESTINATION ${KDE_INSTALL_LIBEXECDIR}) 102 | 103 | install(FILES ${CMAKE_BINARY_DIR}/pam_kwallet_init.desktop DESTINATION ${KDE_INSTALL_AUTOSTARTDIR}) 104 | 105 | ecm_install_configured_files(INPUT plasma-kwallet-pam.service.in @ONLY DESTINATION 106 | ${KDE_INSTALL_SYSTEMDUSERUNITDIR}) 107 | -------------------------------------------------------------------------------- /pam_kwallet_init.desktop.cmake: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=KWallet PAM Socket Connection 3 | Name[ar]=اتصال بمقبس التوثيق المحفظة ك 4 | Name[ast]=Conexón de la ralura PAM de KWallet 5 | Name[az]=KWallet PAM Socket Bağlantısı 6 | Name[bg]=Връзка с KWallet PAM сокет 7 | Name[ca]=Connexió amb el sòcol PAM del KWallet 8 | Name[ca@valencia]=Connexió amb el sòcol PAM de KWallet 9 | Name[cs]=Připojení Socketu Kwallet PAM 10 | Name[da]=KWallet PAM-sokkel-forbindelse 11 | Name[de]=Verbindung zu KWallet-PAM-Socket 12 | Name[el]=Σύνδεση υποδοχής KWallet PAM 13 | Name[en_GB]=KWallet PAM Socket Connection 14 | Name[eo]=KWallet PAM konektinga konekto 15 | Name[es]=Conexión con el «socket» PAM de KWallet 16 | Name[et]=KDE turvalaeka PAM-sokli ühendus 17 | Name[eu]=KWallet PAM socket konexioa 18 | Name[fi]=KWalletin PAM-pistokeyhteys 19 | Name[fr]=Connexion au socket « PAM » de KWallet 20 | Name[gl]=Conexión ao socket PAM de KWallet 21 | Name[he]=חיבור שקע PAM ל־KWallet 22 | Name[hi]=के-वालेट पीएएम सोकेट कनेक्शन 23 | Name[hu]=KWallet PAM socket-kapcsolat 24 | Name[ia]=Connexion de PAM Socket de KWallet 25 | Name[id]=KWallet PAM Socket Connection 26 | Name[ie]=Conexion al socket PAM de KWallet 27 | Name[is]=KWallet PAM sökkultenging 28 | Name[it]=Connessione socket PAM di KWallet 29 | Name[ka]=KWallet PAM-ის სოკეტთან დაკავშირება 30 | Name[ko]=KWallet PAM 소켓 연결 31 | Name[lt]=KWallet PAM lizdo ryšys 32 | Name[lv]=KWallet PAM ligzdas savienojums 33 | Name[nl]=KWallet verbinding met PAM-socket 34 | Name[nn]=KWallet PAM-socket-tilkopling 35 | Name[pa]=ਕੇ-ਵਾਲਟ PAM ਸਾਕਟ ਕਨੈਕਸ਼ਨ 36 | Name[pl]=Połączenie do gniazda PAM Portfela 37 | Name[pt]=Ligação por 'Socket' entre PAM e o KWallet 38 | Name[pt_BR]=Conexão do Socket PAM do KWallet 39 | Name[ro]=Conexiune la soclu PAM KWallet 40 | Name[ru]=Интеграция KWallet и PAM 41 | Name[sa]=KWallet PAM सॉकेट संयोजनम् 42 | Name[sk]=Pripojenie socketu KWallet PAM 43 | Name[sl]=Povezava z vtičem PAM KWalleta 44 | Name[sr]=Веза са К‑новчаниковим ПАМ сокетом 45 | Name[sr@ijekavian]=Веза са К‑новчаниковим ПАМ сокетом 46 | Name[sr@ijekavianlatin]=Veza sa K‑novčanikovim PAM soketom 47 | Name[sr@latin]=Veza sa K‑novčanikovim PAM soketom 48 | Name[sv]=Plånbokens PAM-uttagsanslutning 49 | Name[tg]=Пайвасти бастагоҳи KWallet PAM 50 | Name[tr]=K Cüzdan PAM Yuvası Bağlantısı 51 | Name[uk]=З’єднання із сокетом PAM KWallet 52 | Name[vi]=Kết nối ổ cắm PAM KWallet 53 | Name[zh_CN]=KWallet PAM 套接字连接 54 | Name[zh_TW]=KWallet PAM Socket 連線 55 | Comment=Connect to KWallet PAM socket 56 | Comment[ar]=اتصل بمقبس التوثيق محفظة ك 57 | Comment[ast]=Conéctase a la ralura PAM de KWallet 58 | Comment[az]=KWallet PAM socket'ə qoşulmaq 59 | Comment[bg]=Свързване с KWallet PAM сокет 60 | Comment[ca]=Connecta amb un sòcol PAM del KWallet 61 | Comment[ca@valencia]=Connecta amb un sòcol PAM de KWallet 62 | Comment[cs]=Připojit k socketu Kwallet PAM 63 | Comment[da]=Forbind til KWallet PAM-sokkel 64 | Comment[de]=Zum KWallet-PAM-Socket verbinden 65 | Comment[el]=Σύνδεση με υποδοχή KWallet PAM 66 | Comment[en_GB]=Connect to KWallet PAM socket 67 | Comment[eo]=Konektu al KWallet PAM-konektingo 68 | Comment[es]=Conectar con el «socket» PAM de KWallet 69 | Comment[et]=Ühendumine KDE turvalaeka PAM-sokliga 70 | Comment[eu]=Konektatu KWallet-en PAM socket-era 71 | Comment[fi]=Yhteys KWalletin PAM-pistokkeeseen 72 | Comment[fr]=Connecter au socket PAM de KWallet 73 | Comment[gl]=Conectar ao socket PAM de KWallet. 74 | Comment[he]=חיבור לשקע PAM ל־KWallet 75 | Comment[hi]=के-वालेट पीएएम सोकेट से संपर्क जोडें 76 | Comment[hu]=Kapcsolódás KWallet PAM sockethez 77 | Comment[ia]=Connecte a PAMsoccket de KWallet 78 | Comment[id]=Koneksikan ke soket KWallet PAM 79 | Comment[ie]=Conexer al socket PAM de KWallet 80 | Comment[is]=Tengjast við KWallet PAM sökkul 81 | Comment[it]=Connetti al socket PAM di KWallet 82 | Comment[ka]=KWallet PAM-ის სოკეტთან დაკავშირება 83 | Comment[ko]=KWallet PAM 소켓에 연결할 수 없음 84 | Comment[lt]=Prisijungti prie KWallet PAM lizdo 85 | Comment[lv]=Savienoties ar „KWallet“ PAM ligzdu 86 | Comment[nl]=Verbinden met KWallet PAM-socket 87 | Comment[nn]=Kopla til KWallet PAM-socket 88 | Comment[pa]=ਕੇ-ਵਾਲਟ PAM ਸਾਕਟ ਨਾਲ ਕਨੈਕਟ ਕਰੋ 89 | Comment[pl]=Połącz z gniazdem PAM Portfela 90 | Comment[pt]=Ligar ao 'socket' de PAM do KWallet 91 | Comment[pt_BR]=Conecta ao socket PAM do KWallet 92 | Comment[ro]=Conectează la soclul PAM KWallet 93 | Comment[ru]=Подключение PAM к KWallet по сокету 94 | Comment[sa]=KWallet PAM सॉकेट् इत्यनेन सह संयोजयन्तु 95 | Comment[sk]=Pripojiť na KWallet PAM socket 96 | Comment[sl]=Povežite se z vtičem PAM KWalleta 97 | Comment[sr]=Повежи се на К‑новчаников ПАМ сокет 98 | Comment[sr@ijekavian]=Повежи се на К‑новчаников ПАМ сокет 99 | Comment[sr@ijekavianlatin]=Poveži se na K‑novčanikov PAM soket 100 | Comment[sr@latin]=Poveži se na K‑novčanikov PAM soket 101 | Comment[sv]=Anslut till plånbokens PAM-uttag 102 | Comment[tg]=Пайваст шудан ба бастагоҳи KWallet PAM 103 | Comment[tr]=K Cüzdan PAM yuvasına bağlan 104 | Comment[uk]=З’єднатися із сокетом PAM KWallet 105 | Comment[vi]=Kết nối đến ổ cắm PAM KWallet 106 | Comment[zh_CN]=连接到 KWallet PAM 套接字 107 | Comment[zh_TW]=連線到 KWallet PAM socket 108 | Exec=${CMAKE_INSTALL_FULL_LIBEXECDIR}/pam_kwallet_init 109 | Type=Application 110 | NoDisplay=true 111 | X-KDE-StartupNotify=false 112 | X-KDE-autostart-phase=0 113 | X-systemd-skip=true 114 | -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /LICENSES/LGPL-2.1-or-later.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | 3 | Version 2.1, February 1999 4 | 5 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 6 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies of this license 9 | document, but changing it is not allowed. 10 | 11 | [This is the first released version of the Lesser GPL. It also counts as 12 | the successor of the GNU Library Public License, version 2, hence the version 13 | number 2.1.] 14 | 15 | Preamble 16 | 17 | The licenses for most software are designed to take away your freedom to share 18 | and change it. By contrast, the GNU General Public Licenses are intended to 19 | guarantee your freedom to share and change free software--to make sure the 20 | software is free for all its users. 21 | 22 | This license, the Lesser General Public License, applies to some specially 23 | designated software packages--typically libraries--of the Free Software Foundation 24 | and other authors who decide to use it. You can use it too, but we suggest 25 | you first think carefully about whether this license or the ordinary General 26 | Public License is the better strategy to use in any particular case, based 27 | on the explanations below. 28 | 29 | When we speak of free software, we are referring to freedom of use, not price. 30 | Our General Public Licenses are designed to make sure that you have the freedom 31 | to distribute copies of free software (and charge for this service if you 32 | wish); that you receive source code or can get it if you want it; that you 33 | can change the software and use pieces of it in new free programs; and that 34 | you are informed that you can do these things. 35 | 36 | To protect your rights, we need to make restrictions that forbid distributors 37 | to deny you these rights or to ask you to surrender these rights. These restrictions 38 | translate to certain responsibilities for you if you distribute copies of 39 | the library or if you modify it. 40 | 41 | For example, if you distribute copies of the library, whether gratis or for 42 | a fee, you must give the recipients all the rights that we gave you. You must 43 | make sure that they, too, receive or can get the source code. If you link 44 | other code with the library, you must provide complete object files to the 45 | recipients, so that they can relink them with the library after making changes 46 | to the library and recompiling it. And you must show them these terms so they 47 | know their rights. 48 | 49 | We protect your rights with a two-step method: (1) we copyright the library, 50 | and (2) we offer you this license, which gives you legal permission to copy, 51 | distribute and/or modify the library. 52 | 53 | To protect each distributor, we want to make it very clear that there is no 54 | warranty for the free library. Also, if the library is modified by someone 55 | else and passed on, the recipients should know that what they have is not 56 | the original version, so that the original author's reputation will not be 57 | affected by problems that might be introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of any free 60 | program. We wish to make sure that a company cannot effectively restrict the 61 | users of a free program by obtaining a restrictive license from a patent holder. 62 | Therefore, we insist that any patent license obtained for a version of the 63 | library must be consistent with the full freedom of use specified in this 64 | license. 65 | 66 | Most GNU software, including some libraries, is covered by the ordinary GNU 67 | General Public License. This license, the GNU Lesser General Public License, 68 | applies to certain designated libraries, and is quite different from the ordinary 69 | General Public License. We use this license for certain libraries in order 70 | to permit linking those libraries into non-free programs. 71 | 72 | When a program is linked with a library, whether statically or using a shared 73 | library, the combination of the two is legally speaking a combined work, a 74 | derivative of the original library. The ordinary General Public License therefore 75 | permits such linking only if the entire combination fits its criteria of freedom. 76 | The Lesser General Public License permits more lax criteria for linking other 77 | code with the library. 78 | 79 | We call this license the "Lesser" General Public License because it does Less 80 | to protect the user's freedom than the ordinary General Public License. It 81 | also provides other free software developers Less of an advantage over competing 82 | non-free programs. These disadvantages are the reason we use the ordinary 83 | General Public License for many libraries. However, the Lesser license provides 84 | advantages in certain special circumstances. 85 | 86 | For example, on rare occasions, there may be a special need to encourage the 87 | widest possible use of a certain library, so that it becomes a de-facto standard. 88 | To achieve this, non-free programs must be allowed to use the library. A more 89 | frequent case is that a free library does the same job as widely used non-free 90 | libraries. In this case, there is little to gain by limiting the free library 91 | to free software only, so we use the Lesser General Public License. 92 | 93 | In other cases, permission to use a particular library in non-free programs 94 | enables a greater number of people to use a large body of free software. For 95 | example, permission to use the GNU C Library in non-free programs enables 96 | many more people to use the whole GNU operating system, as well as its variant, 97 | the GNU/Linux operating system. 98 | 99 | Although the Lesser General Public License is Less protective of the users' 100 | freedom, it does ensure that the user of a program that is linked with the 101 | Library has the freedom and the wherewithal to run that program using a modified 102 | version of the Library. 103 | 104 | The precise terms and conditions for copying, distribution and modification 105 | follow. Pay close attention to the difference between a "work based on the 106 | library" and a "work that uses the library". The former contains code derived 107 | from the library, whereas the latter must be combined with the library in 108 | order to run. 109 | 110 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 111 | 112 | 0. This License Agreement applies to any software library or other program 113 | which contains a notice placed by the copyright holder or other authorized 114 | party saying it may be distributed under the terms of this Lesser General 115 | Public License (also called "this License"). Each licensee is addressed as 116 | "you". 117 | 118 | A "library" means a collection of software functions and/or data prepared 119 | so as to be conveniently linked with application programs (which use some 120 | of those functions and data) to form executables. 121 | 122 | The "Library", below, refers to any such software library or work which has 123 | been distributed under these terms. A "work based on the Library" means either 124 | the Library or any derivative work under copyright law: that is to say, a 125 | work containing the Library or a portion of it, either verbatim or with modifications 126 | and/or translated straightforwardly into another language. (Hereinafter, translation 127 | is included without limitation in the term "modification".) 128 | 129 | "Source code" for a work means the preferred form of the work for making modifications 130 | to it. For a library, complete source code means all the source code for all 131 | modules it contains, plus any associated interface definition files, plus 132 | the scripts used to control compilation and installation of the library. 133 | 134 | Activities other than copying, distribution and modification are not covered 135 | by this License; they are outside its scope. The act of running a program 136 | using the Library is not restricted, and output from such a program is covered 137 | only if its contents constitute a work based on the Library (independent of 138 | the use of the Library in a tool for writing it). Whether that is true depends 139 | on what the Library does and what the program that uses the Library does. 140 | 141 | 1. You may copy and distribute verbatim copies of the Library's complete source 142 | code as you receive it, in any medium, provided that you conspicuously and 143 | appropriately publish on each copy an appropriate copyright notice and disclaimer 144 | of warranty; keep intact all the notices that refer to this License and to 145 | the absence of any warranty; and distribute a copy of this License along with 146 | the Library. 147 | 148 | You may charge a fee for the physical act of transferring a copy, and you 149 | may at your option offer warranty protection in exchange for a fee. 150 | 151 | 2. You may modify your copy or copies of the Library or any portion of it, 152 | thus forming a work based on the Library, and copy and distribute such modifications 153 | or work under the terms of Section 1 above, provided that you also meet all 154 | of these conditions: 155 | 156 | a) The modified work must itself be a software library. 157 | 158 | b) You must cause the files modified to carry prominent notices stating that 159 | you changed the files and the date of any change. 160 | 161 | c) You must cause the whole of the work to be licensed at no charge to all 162 | third parties under the terms of this License. 163 | 164 | d) If a facility in the modified Library refers to a function or a table of 165 | data to be supplied by an application program that uses the facility, other 166 | than as an argument passed when the facility is invoked, then you must make 167 | a good faith effort to ensure that, in the event an application does not supply 168 | such function or table, the facility still operates, and performs whatever 169 | part of its purpose remains meaningful. 170 | 171 | (For example, a function in a library to compute square roots has a purpose 172 | that is entirely well-defined independent of the application. Therefore, Subsection 173 | 2d requires that any application-supplied function or table used by this function 174 | must be optional: if the application does not supply it, the square root function 175 | must still compute square roots.) 176 | 177 | These requirements apply to the modified work as a whole. If identifiable 178 | sections of that work are not derived from the Library, and can be reasonably 179 | considered independent and separate works in themselves, then this License, 180 | and its terms, do not apply to those sections when you distribute them as 181 | separate works. But when you distribute the same sections as part of a whole 182 | which is a work based on the Library, the distribution of the whole must be 183 | on the terms of this License, whose permissions for other licensees extend 184 | to the entire whole, and thus to each and every part regardless of who wrote 185 | it. 186 | 187 | Thus, it is not the intent of this section to claim rights or contest your 188 | rights to work written entirely by you; rather, the intent is to exercise 189 | the right to control the distribution of derivative or collective works based 190 | on the Library. 191 | 192 | In addition, mere aggregation of another work not based on the Library with 193 | the Library (or with a work based on the Library) on a volume of a storage 194 | or distribution medium does not bring the other work under the scope of this 195 | License. 196 | 197 | 3. You may opt to apply the terms of the ordinary GNU General Public License 198 | instead of this License to a given copy of the Library. To do this, you must 199 | alter all the notices that refer to this License, so that they refer to the 200 | ordinary GNU General Public License, version 2, instead of to this License. 201 | (If a newer version than version 2 of the ordinary GNU General Public License 202 | has appeared, then you can specify that version instead if you wish.) Do not 203 | make any other change in these notices. 204 | 205 | Once this change is made in a given copy, it is irreversible for that copy, 206 | so the ordinary GNU General Public License applies to all subsequent copies 207 | and derivative works made from that copy. 208 | 209 | This option is useful when you wish to copy part of the code of the Library 210 | into a program that is not a library. 211 | 212 | 4. You may copy and distribute the Library (or a portion or derivative of 213 | it, under Section 2) in object code or executable form under the terms of 214 | Sections 1 and 2 above provided that you accompany it with the complete corresponding 215 | machine-readable source code, which must be distributed under the terms of 216 | Sections 1 and 2 above on a medium customarily used for software interchange. 217 | 218 | If distribution of object code is made by offering access to copy from a designated 219 | place, then offering equivalent access to copy the source code from the same 220 | place satisfies the requirement to distribute the source code, even though 221 | third parties are not compelled to copy the source along with the object code. 222 | 223 | 5. A program that contains no derivative of any portion of the Library, but 224 | is designed to work with the Library by being compiled or linked with it, 225 | is called a "work that uses the Library". Such a work, in isolation, is not 226 | a derivative work of the Library, and therefore falls outside the scope of 227 | this License. 228 | 229 | However, linking a "work that uses the Library" with the Library creates an 230 | executable that is a derivative of the Library (because it contains portions 231 | of the Library), rather than a "work that uses the library". The executable 232 | is therefore covered by this License. Section 6 states terms for distribution 233 | of such executables. 234 | 235 | When a "work that uses the Library" uses material from a header file that 236 | is part of the Library, the object code for the work may be a derivative work 237 | of the Library even though the source code is not. Whether this is true is 238 | especially significant if the work can be linked without the Library, or if 239 | the work is itself a library. The threshold for this to be true is not precisely 240 | defined by law. 241 | 242 | If such an object file uses only numerical parameters, data structure layouts 243 | and accessors, and small macros and small inline functions (ten lines or less 244 | in length), then the use of the object file is unrestricted, regardless of 245 | whether it is legally a derivative work. (Executables containing this object 246 | code plus portions of the Library will still fall under Section 6.) 247 | 248 | Otherwise, if the work is a derivative of the Library, you may distribute 249 | the object code for the work under the terms of Section 6. Any executables 250 | containing that work also fall under Section 6, whether or not they are linked 251 | directly with the Library itself. 252 | 253 | 6. As an exception to the Sections above, you may also combine or link a "work 254 | that uses the Library" with the Library to produce a work containing portions 255 | of the Library, and distribute that work under terms of your choice, provided 256 | that the terms permit modification of the work for the customer's own use 257 | and reverse engineering for debugging such modifications. 258 | 259 | You must give prominent notice with each copy of the work that the Library 260 | is used in it and that the Library and its use are covered by this License. 261 | You must supply a copy of this License. If the work during execution displays 262 | copyright notices, you must include the copyright notice for the Library among 263 | them, as well as a reference directing the user to the copy of this License. 264 | Also, you must do one of these things: 265 | 266 | a) Accompany the work with the complete corresponding machine-readable source 267 | code for the Library including whatever changes were used in the work (which 268 | must be distributed under Sections 1 and 2 above); and, if the work is an 269 | executable linked with the Library, with the complete machine-readable "work 270 | that uses the Library", as object code and/or source code, so that the user 271 | can modify the Library and then relink to produce a modified executable containing 272 | the modified Library. (It is understood that the user who changes the contents 273 | of definitions files in the Library will not necessarily be able to recompile 274 | the application to use the modified definitions.) 275 | 276 | b) Use a suitable shared library mechanism for linking with the Library. A 277 | suitable mechanism is one that (1) uses at run time a copy of the library 278 | already present on the user's computer system, rather than copying library 279 | functions into the executable, and (2) will operate properly with a modified 280 | version of the library, if the user installs one, as long as the modified 281 | version is interface-compatible with the version that the work was made with. 282 | 283 | c) Accompany the work with a written offer, valid for at least three years, 284 | to give the same user the materials specified in Subsection 6a, above, for 285 | a charge no more than the cost of performing this distribution. 286 | 287 | d) If distribution of the work is made by offering access to copy from a designated 288 | place, offer equivalent access to copy the above specified materials from 289 | the same place. 290 | 291 | e) Verify that the user has already received a copy of these materials or 292 | that you have already sent this user a copy. 293 | 294 | For an executable, the required form of the "work that uses the Library" must 295 | include any data and utility programs needed for reproducing the executable 296 | from it. However, as a special exception, the materials to be distributed 297 | need not include anything that is normally distributed (in either source or 298 | binary form) with the major components (compiler, kernel, and so on) of the 299 | operating system on which the executable runs, unless that component itself 300 | accompanies the executable. 301 | 302 | It may happen that this requirement contradicts the license restrictions of 303 | other proprietary libraries that do not normally accompany the operating system. 304 | Such a contradiction means you cannot use both them and the Library together 305 | in an executable that you distribute. 306 | 307 | 7. You may place library facilities that are a work based on the Library side-by-side 308 | in a single library together with other library facilities not covered by 309 | this License, and distribute such a combined library, provided that the separate 310 | distribution of the work based on the Library and of the other library facilities 311 | is otherwise permitted, and provided that you do these two things: 312 | 313 | a) Accompany the combined library with a copy of the same work based on the 314 | Library, uncombined with any other library facilities. This must be distributed 315 | under the terms of the Sections above. 316 | 317 | b) Give prominent notice with the combined library of the fact that part of 318 | it is a work based on the Library, and explaining where to find the accompanying 319 | uncombined form of the same work. 320 | 321 | 8. You may not copy, modify, sublicense, link with, or distribute the Library 322 | except as expressly provided under this License. Any attempt otherwise to 323 | copy, modify, sublicense, link with, or distribute the Library is void, and 324 | will automatically terminate your rights under this License. However, parties 325 | who have received copies, or rights, from you under this License will not 326 | have their licenses terminated so long as such parties remain in full compliance. 327 | 328 | 9. You are not required to accept this License, since you have not signed 329 | it. However, nothing else grants you permission to modify or distribute the 330 | Library or its derivative works. These actions are prohibited by law if you 331 | do not accept this License. Therefore, by modifying or distributing the Library 332 | (or any work based on the Library), you indicate your acceptance of this License 333 | to do so, and all its terms and conditions for copying, distributing or modifying 334 | the Library or works based on it. 335 | 336 | 10. Each time you redistribute the Library (or any work based on the Library), 337 | the recipient automatically receives a license from the original licensor 338 | to copy, distribute, link with or modify the Library subject to these terms 339 | and conditions. You may not impose any further restrictions on the recipients' 340 | exercise of the rights granted herein. You are not responsible for enforcing 341 | compliance by third parties with this License. 342 | 343 | 11. If, as a consequence of a court judgment or allegation of patent infringement 344 | or for any other reason (not limited to patent issues), conditions are imposed 345 | on you (whether by court order, agreement or otherwise) that contradict the 346 | conditions of this License, they do not excuse you from the conditions of 347 | this License. If you cannot distribute so as to satisfy simultaneously your 348 | obligations under this License and any other pertinent obligations, then as 349 | a consequence you may not distribute the Library at all. For example, if a 350 | patent license would not permit royalty-free redistribution of the Library 351 | by all those who receive copies directly or indirectly through you, then the 352 | only way you could satisfy both it and this License would be to refrain entirely 353 | from distribution of the Library. 354 | 355 | If any portion of this section is held invalid or unenforceable under any 356 | particular circumstance, the balance of the section is intended to apply, 357 | and the section as a whole is intended to apply in other circumstances. 358 | 359 | It is not the purpose of this section to induce you to infringe any patents 360 | or other property right claims or to contest validity of any such claims; 361 | this section has the sole purpose of protecting the integrity of the free 362 | software distribution system which is implemented by public license practices. 363 | Many people have made generous contributions to the wide range of software 364 | distributed through that system in reliance on consistent application of that 365 | system; it is up to the author/donor to decide if he or she is willing to 366 | distribute software through any other system and a licensee cannot impose 367 | that choice. 368 | 369 | This section is intended to make thoroughly clear what is believed to be a 370 | consequence of the rest of this License. 371 | 372 | 12. If the distribution and/or use of the Library is restricted in certain 373 | countries either by patents or by copyrighted interfaces, the original copyright 374 | holder who places the Library under this License may add an explicit geographical 375 | distribution limitation excluding those countries, so that distribution is 376 | permitted only in or among countries not thus excluded. In such case, this 377 | License incorporates the limitation as if written in the body of this License. 378 | 379 | 13. The Free Software Foundation may publish revised and/or new versions of 380 | the Lesser General Public License from time to time. Such new versions will 381 | be similar in spirit to the present version, but may differ in detail to address 382 | new problems or concerns. 383 | 384 | Each version is given a distinguishing version number. If the Library specifies 385 | a version number of this License which applies to it and "any later version", 386 | you have the option of following the terms and conditions either of that version 387 | or of any later version published by the Free Software Foundation. If the 388 | Library does not specify a license version number, you may choose any version 389 | ever published by the Free Software Foundation. 390 | 391 | 14. If you wish to incorporate parts of the Library into other free programs 392 | whose distribution conditions are incompatible with these, write to the author 393 | to ask for permission. For software which is copyrighted by the Free Software 394 | Foundation, write to the Free Software Foundation; we sometimes make exceptions 395 | for this. Our decision will be guided by the two goals of preserving the free 396 | status of all derivatives of our free software and of promoting the sharing 397 | and reuse of software generally. 398 | 399 | NO WARRANTY 400 | 401 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR 402 | THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE 403 | STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY 404 | "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 405 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 406 | FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 407 | OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 408 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 409 | 410 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 411 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 412 | THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 413 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE 414 | OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA 415 | OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES 416 | OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH 417 | HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 418 | 419 | END OF TERMS AND CONDITIONS 420 | 421 | How to Apply These Terms to Your New Libraries 422 | 423 | If you develop a new library, and you want it to be of the greatest possible 424 | use to the public, we recommend making it free software that everyone can 425 | redistribute and change. You can do so by permitting redistribution under 426 | these terms (or, alternatively, under the terms of the ordinary General Public 427 | License). 428 | 429 | To apply these terms, attach the following notices to the library. It is safest 430 | to attach them to the start of each source file to most effectively convey 431 | the exclusion of warranty; and each file should have at least the "copyright" 432 | line and a pointer to where the full notice is found. 433 | 434 | one line to give the library's name and an idea of what it does. 435 | Copyright (C) year name of author 436 | 437 | This library is free software; you can redistribute it and/or modify it under 438 | the terms of the GNU Lesser General Public License as published by the Free 439 | Software Foundation; either version 2.1 of the License, or (at your option) 440 | any later version. 441 | 442 | This library is distributed in the hope that it will be useful, but WITHOUT 443 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 444 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 445 | details. 446 | 447 | You should have received a copy of the GNU Lesser General Public License along 448 | with this library; if not, write to the Free Software Foundation, Inc., 51 449 | Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information 450 | on how to contact you by electronic and paper mail. 451 | 452 | You should also get your employer (if you work as a programmer) or your school, 453 | if any, to sign a "copyright disclaimer" for the library, if necessary. Here 454 | is a sample; alter the names: 455 | 456 | Yoyodyne, Inc., hereby disclaims all copyright interest in 457 | the library `Frob' (a library for tweaking knobs) written 458 | by James Random Hacker. 459 | 460 | signature of Ty Coon, 1 April 1990 461 | Ty Coon, President of Vice 462 | That's all there is to it! 463 | -------------------------------------------------------------------------------- /pam_kwallet.c: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2014 Alejandro Fiestas Olivares 3 | 4 | SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define PAM_SM_PASSWORD 19 | #define PAM_SM_SESSION 20 | #define PAM_SM_AUTH 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | /* PAM headers. 30 | * 31 | * There are three styles in play: 32 | * - Apple, which has no pam_ext.h, does have pam_appl.h, does have pam_syslog 33 | * - Linux, which has pam_ext.h, does have pam_appl.h, does have pam_syslog 34 | * - BSD, which has no pam_ext.h, does have pam_appl.h, but no pam_syslog 35 | * In the latter case, #define pam_syslog away. 36 | */ 37 | #ifdef __APPLE__ 38 | #include "pam_darwin.h" 39 | #include 40 | #else 41 | #include 42 | #ifdef HAVE_PAM_EXT 43 | /* "Linux style" */ 44 | #include 45 | #include 46 | #endif 47 | #ifdef HAVE_PAM_APPL 48 | /* "BSD style" .. see also __APPLE__, above */ 49 | #include 50 | #ifndef HAVE_PAM_EXT 51 | /* FreeBSD has no pam_syslog(), va-macro it away */ 52 | #define pam_syslog(...) 53 | #endif 54 | #endif 55 | #endif 56 | 57 | #define KWALLET_PAM_KEYSIZE 56 58 | #define KWALLET_PAM_SALTSIZE 56 59 | #define KWALLET_PAM_ITERATIONS 50000 60 | 61 | // Parameters 62 | const static char *kdehome = NULL; 63 | const static char *kwalletd = NULL; 64 | const static char *socketPath = NULL; 65 | static int force_run = 0; 66 | 67 | const static char * const kwalletPamDataKey = "kwallet5_key"; 68 | const static char * const logPrefix = "pam_kwallet5"; 69 | const static char * const envVar = "PAM_KWALLET5_LOGIN"; 70 | 71 | static int argumentsParsed = -1; 72 | 73 | int kwallet_hash(pam_handle_t *pamh, const char *passphrase, struct passwd *userInfo, char *key); 74 | 75 | static void parseArguments(int argc, const char **argv) 76 | { 77 | //If already parsed 78 | if (argumentsParsed != -1) { 79 | return; 80 | } 81 | 82 | int x = 0; 83 | for (;x < argc; ++x) { 84 | if (strstr(argv[x], "kdehome=") != NULL) { 85 | kdehome = argv[x] + 8; 86 | } else if (strstr(argv[x], "kwalletd=") != NULL) { 87 | kwalletd = argv[x] + 9; 88 | } else if (strstr(argv[x], "socketPath=") != NULL) { 89 | socketPath= argv[x] + 11; 90 | } else if (strcmp(argv[x], "force_run") == 0) { 91 | force_run = 1; 92 | } 93 | } 94 | if (kdehome == NULL) { 95 | kdehome = ".local/share"; 96 | } 97 | if (kwalletd == NULL) { 98 | kwalletd = KWALLETD_BIN_PATH; 99 | } 100 | } 101 | 102 | static const char* get_env(pam_handle_t *ph, const char *name) 103 | { 104 | const char *env = pam_getenv (ph, name); 105 | if (env && env[0]) { 106 | return env; 107 | } 108 | 109 | env = getenv (name); 110 | if (env && env[0]) { 111 | return env; 112 | } 113 | 114 | return NULL; 115 | } 116 | 117 | static int set_env(pam_handle_t *pamh, const char *name, const char *value) 118 | { 119 | if (setenv(name, value, 1) < 0) { 120 | pam_syslog(pamh, LOG_WARNING, "%s: Couldn't setenv %s = %s", logPrefix, name, value); 121 | //We do not return because pam_putenv might work 122 | } 123 | 124 | size_t pamEnvSize = strlen(name) + strlen(value) + 2; //2 is for = and \0 125 | char *pamEnv = malloc(pamEnvSize); 126 | if (!pamEnv) { 127 | pam_syslog(pamh, LOG_WARNING, "%s: Impossible to allocate memory for pamEnv", logPrefix); 128 | return -1; 129 | } 130 | 131 | snprintf (pamEnv, pamEnvSize, "%s=%s", name, value); 132 | int ret = pam_putenv(pamh, pamEnv); 133 | free(pamEnv); 134 | 135 | return ret; 136 | } 137 | 138 | /** 139 | * Code copied from gkr-pam-module.c, GPL2+ 140 | */ 141 | static void wipeString(char *str) 142 | { 143 | if (!str) { 144 | return; 145 | } 146 | 147 | const size_t len = strlen (str); 148 | #if HAVE_EXPLICIT_BZERO 149 | explicit_bzero(str, len); 150 | #else 151 | volatile char *vp; 152 | 153 | /* Defeats some optimizations */ 154 | memset (str, 0xAA, len); 155 | memset (str, 0xBB, len); 156 | 157 | /* Defeats others */ 158 | vp = (volatile char*)str; 159 | while (*vp) { 160 | *(vp++) = 0xAA; 161 | } 162 | #endif 163 | 164 | free (str); 165 | } 166 | 167 | static int prompt_for_password(pam_handle_t *pamh) 168 | { 169 | int result; 170 | 171 | //Get the function we have to call 172 | const struct pam_conv *conv; 173 | result = pam_get_item(pamh, PAM_CONV, (const void**)&conv); 174 | if (result != PAM_SUCCESS) { 175 | return result; 176 | } 177 | 178 | //prepare the message 179 | struct pam_message message; 180 | memset (&message, 0, sizeof(message)); 181 | message.msg_style = PAM_PROMPT_ECHO_OFF; 182 | message.msg = "Password: "; 183 | 184 | //We only need one message, but we still have to send it in an array 185 | const struct pam_message *msgs[1]; 186 | msgs[0] = &message; 187 | 188 | 189 | //Sending the message, asking for password 190 | struct pam_response *response = NULL; 191 | memset (&response, 0, sizeof(response)); 192 | result = (conv->conv) (1, msgs, &response, conv->appdata_ptr); 193 | if (result != PAM_SUCCESS) { 194 | goto cleanup; 195 | } 196 | 197 | //If we got no password, just return; 198 | if (response[0].resp == NULL) { 199 | result = PAM_CONV_ERR; 200 | goto cleanup; 201 | } 202 | 203 | //Set the password in PAM memory 204 | char *password = response[0].resp; 205 | result = pam_set_item(pamh, PAM_AUTHTOK, password); 206 | wipeString(password); 207 | 208 | if (result != PAM_SUCCESS) { 209 | goto cleanup; 210 | } 211 | 212 | cleanup: 213 | free(response); 214 | return result; 215 | } 216 | 217 | static void cleanup_free(pam_handle_t *pamh, void *ptr, int error_status) 218 | { 219 | free(ptr); 220 | } 221 | 222 | static int is_graphical_session(pam_handle_t *pamh) 223 | { 224 | //Detect a graphical session 225 | const char *pam_tty = NULL, *pam_xdisplay = NULL, 226 | *xdg_session_type = NULL; 227 | 228 | pam_get_item(pamh, PAM_TTY, (const void**) &pam_tty); 229 | #ifdef PAM_XDISPLAY 230 | pam_get_item(pamh, PAM_XDISPLAY, (const void**) &pam_xdisplay); 231 | #endif 232 | xdg_session_type = get_env(pamh, "XDG_SESSION_TYPE"); 233 | 234 | return (pam_xdisplay && strlen(pam_xdisplay) != 0) 235 | || (pam_tty && pam_tty[0] == ':') 236 | || (xdg_session_type && strcmp(xdg_session_type, "x11") == 0) 237 | || (xdg_session_type && strcmp(xdg_session_type, "wayland") == 0); 238 | } 239 | 240 | PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) 241 | { 242 | pam_syslog(pamh, LOG_DEBUG, "%s: pam_sm_authenticate\n", logPrefix); 243 | if (get_env(pamh, envVar) != NULL) { 244 | pam_syslog(pamh, LOG_INFO, "%s: we were already executed", logPrefix); 245 | return PAM_IGNORE; 246 | } 247 | 248 | parseArguments(argc, argv); 249 | 250 | int result; 251 | 252 | //Fetch the user, needed to get user information 253 | const char *username; 254 | result = pam_get_user(pamh, &username, NULL); 255 | if (result != PAM_SUCCESS) { 256 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't get username %s", 257 | logPrefix, pam_strerror(pamh, result)); 258 | return PAM_IGNORE;//Since we are not an essential module, just make pam ignore us 259 | } 260 | 261 | struct passwd *userInfo; 262 | userInfo = getpwnam(username); 263 | if (!userInfo) { 264 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't get user info (passwd) info", logPrefix); 265 | return PAM_IGNORE; 266 | } 267 | 268 | if (userInfo->pw_uid == 0) { 269 | pam_syslog(pamh, LOG_DEBUG, "%s: Refusing to do anything for the root user", logPrefix); 270 | return PAM_IGNORE; 271 | } 272 | 273 | const char *password; 274 | result = pam_get_item(pamh, PAM_AUTHTOK, (const void**)&password); 275 | 276 | if (result != PAM_SUCCESS) { 277 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't get password %s", logPrefix, 278 | pam_strerror(pamh, result)); 279 | return PAM_IGNORE; 280 | } 281 | 282 | if (!password) { 283 | pam_syslog(pamh, LOG_NOTICE, "%s: Couldn't get password (it is empty)", logPrefix); 284 | //Asking for the password ourselves 285 | result = prompt_for_password(pamh); 286 | if (result != PAM_SUCCESS) { 287 | pam_syslog(pamh, LOG_ERR, "%s: Prompt for password failed %s", 288 | logPrefix, pam_strerror(pamh, result) 289 | ); 290 | return PAM_IGNORE; 291 | } 292 | } 293 | 294 | //even though we just set it, better check to be 100% sure 295 | result = pam_get_item(pamh, PAM_AUTHTOK, (const void**)&password); 296 | if (result != PAM_SUCCESS || !password) { 297 | pam_syslog(pamh, LOG_ERR, "%s: Password is not there even though we set it %s", logPrefix, 298 | pam_strerror(pamh, result)); 299 | return PAM_IGNORE; 300 | } 301 | 302 | if (password[0] == '\0') { 303 | pam_syslog(pamh, LOG_NOTICE, "%s: Empty or missing password, doing nothing", logPrefix); 304 | return PAM_IGNORE; 305 | } 306 | 307 | char *key = strdup(password); 308 | result = pam_set_data(pamh, kwalletPamDataKey, key, cleanup_free); 309 | 310 | if (result != PAM_SUCCESS) { 311 | free(key); 312 | pam_syslog(pamh, LOG_ERR, "%s: Impossible to store the password: %s", logPrefix 313 | , pam_strerror(pamh, result)); 314 | return PAM_IGNORE; 315 | } 316 | 317 | //TODO unlock kwallet that is already executed 318 | return PAM_IGNORE; 319 | } 320 | 321 | static int drop_privileges(struct passwd *userInfo) 322 | { 323 | /* When dropping privileges from root, the `setgroups` call will 324 | * remove any extraneous groups. If we don't call this, then 325 | * even though our uid has dropped, we may still have groups 326 | * that enable us to do super-user things. This will fail if we 327 | * aren't root, so don't bother checking the return value, this 328 | * is just done as an optimistic privilege dropping function. 329 | */ 330 | setgroups(0, NULL); 331 | 332 | //Change to the user in case we are not it yet 333 | if (setgid (userInfo->pw_gid) < 0 || setuid (userInfo->pw_uid) < 0 || 334 | setegid (userInfo->pw_gid) < 0 || seteuid (userInfo->pw_uid) < 0) { 335 | return -1; 336 | } 337 | 338 | return 0; 339 | } 340 | 341 | static void execute_kwallet(pam_handle_t *pamh, struct passwd *userInfo, int toWalletPipe[2], char *fullSocket) 342 | { 343 | //In the child pam_syslog does not work, using syslog directly 344 | 345 | //keep stderr open so socket doesn't returns us that fd 346 | int x = 3; 347 | //Set FD_CLOEXEC on fd that are not of interest of kwallet 348 | for (; x < 64; ++x) { 349 | if (x != toWalletPipe[0]) { 350 | fcntl(x, F_SETFD, FD_CLOEXEC); 351 | } 352 | } 353 | 354 | //This is the side of the pipe PAM will send the hash to 355 | close (toWalletPipe[1]); 356 | 357 | //Change to the user in case we are not it yet 358 | if (drop_privileges(userInfo) < 0) { 359 | syslog(LOG_ERR, "%s: could not set gid/uid/euid/egit for kwalletd", logPrefix); 360 | goto cleanup; 361 | } 362 | 363 | int envSocket; 364 | if ((envSocket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 365 | syslog(LOG_ERR, "%s: couldn't create socket", logPrefix); 366 | goto cleanup; 367 | } 368 | 369 | struct sockaddr_un local = {}; 370 | local.sun_family = AF_UNIX; 371 | 372 | if (strlen(fullSocket) > sizeof(local.sun_path)) { 373 | syslog(LOG_ERR, "%s: socket path %s too long to open", 374 | logPrefix, fullSocket); 375 | free(fullSocket); 376 | goto cleanup; 377 | } 378 | strcpy(local.sun_path, fullSocket); 379 | unlink(local.sun_path);//Just in case it exists from a previous login 380 | 381 | syslog(LOG_DEBUG, "%s: final socket path: %s", logPrefix, local.sun_path); 382 | 383 | if (bind(envSocket, (struct sockaddr *)&local, sizeof(local)) == -1) { 384 | syslog(LOG_INFO, "%s-kwalletd: Couldn't bind to local file\n", logPrefix); 385 | goto cleanup; 386 | } 387 | 388 | if (listen(envSocket, 5) == -1) { 389 | syslog(LOG_INFO, "%s-kwalletd: Couldn't listen in socket: %d-%s\n", logPrefix, errno, strerror(errno)); 390 | goto cleanup; 391 | } 392 | //finally close stderr 393 | close(2); 394 | 395 | // Fork twice to daemonize kwallet 396 | setsid(); 397 | pid_t pid = fork(); 398 | if (pid != 0) { 399 | if (pid == -1) { 400 | exit(EXIT_FAILURE); 401 | } else { 402 | exit(0); 403 | } 404 | } 405 | 406 | //TODO use a pam argument for full path kwalletd 407 | char pipeInt[4]; 408 | sprintf(pipeInt, "%d", toWalletPipe[0]); 409 | char sockIn[4]; 410 | sprintf(sockIn, "%d", envSocket); 411 | 412 | char *args[] = {strdup(kwalletd), "--pam-login", pipeInt, sockIn, NULL, NULL}; 413 | execve(args[0], args, pam_getenvlist(pamh)); 414 | syslog(LOG_ERR, "%s: could not execute kwalletd from %s", logPrefix, kwalletd); 415 | 416 | cleanup: 417 | exit(EXIT_FAILURE); 418 | } 419 | 420 | static int better_write(int fd, const char *buffer, int len) 421 | { 422 | size_t writtenBytes = 0; 423 | while(writtenBytes < len) { 424 | ssize_t result = write(fd, buffer + writtenBytes, len - writtenBytes); 425 | if (result < 0) { 426 | if (errno != EAGAIN && errno != EINTR) { 427 | return -1; 428 | } 429 | } 430 | writtenBytes += result; 431 | } 432 | 433 | return writtenBytes; 434 | } 435 | 436 | static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const char *kwalletKey) 437 | { 438 | //Just in case we get broken pipe, do not break the pam process.. 439 | struct sigaction sigPipe, oldSigPipe; 440 | memset (&sigPipe, 0, sizeof (sigPipe)); 441 | memset (&oldSigPipe, 0, sizeof (oldSigPipe)); 442 | sigPipe.sa_handler = SIG_IGN; 443 | sigaction (SIGPIPE, &sigPipe, &oldSigPipe); 444 | 445 | int toWalletPipe[2] = { -1, -1}; 446 | if (pipe(toWalletPipe) < 0) { 447 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't create pipes", logPrefix); 448 | } 449 | 450 | const char *socketPrefix = "kwallet5"; 451 | 452 | char *fullSocket = NULL; 453 | if (socketPath) { 454 | size_t needed = snprintf(NULL, 0, "%s/%s_%s%s", socketPath, socketPrefix, userInfo->pw_name, ".socket"); 455 | needed += 1; 456 | fullSocket = malloc(needed); 457 | snprintf(fullSocket, needed, "%s/%s_%s%s", socketPath, socketPrefix, userInfo->pw_name, ".socket"); 458 | } else { 459 | socketPath = get_env(pamh, "XDG_RUNTIME_DIR"); 460 | // Check whether XDG_RUNTIME_DIR is usable 461 | if (socketPath) { 462 | struct stat rundir_stat; 463 | if (stat(socketPath, &rundir_stat) != 0) { 464 | pam_syslog(pamh, LOG_ERR, "%s: Failed to stat %s", logPrefix, socketPath); 465 | socketPath = NULL; 466 | } else if(!S_ISDIR(rundir_stat.st_mode) || (rundir_stat.st_mode & ~S_IFMT) != 0700 467 | || rundir_stat.st_uid != userInfo->pw_uid) { 468 | pam_syslog(pamh, LOG_ERR, "%s: %s has wrong type, perms or ownership", logPrefix, socketPath); 469 | socketPath = NULL; 470 | } 471 | } 472 | 473 | if (socketPath) { 474 | size_t needed = snprintf(NULL, 0, "%s/%s%s", socketPath, socketPrefix, ".socket"); 475 | needed += 1; 476 | fullSocket = malloc(needed); 477 | snprintf(fullSocket, needed, "%s/%s%s", socketPath, socketPrefix, ".socket"); 478 | } else { 479 | size_t needed = snprintf(NULL, 0, "/tmp/%s_%s%s", socketPrefix, userInfo->pw_name, ".socket"); 480 | needed += 1; 481 | fullSocket = malloc(needed); 482 | snprintf(fullSocket, needed, "/tmp/%s_%s%s", socketPrefix, userInfo->pw_name, ".socket"); 483 | } 484 | } 485 | 486 | int result = set_env(pamh, envVar, fullSocket); 487 | if (result != PAM_SUCCESS) { 488 | pam_syslog(pamh, LOG_ERR, "%s: Impossible to set %s env, %s", 489 | logPrefix, envVar, pam_strerror(pamh, result)); 490 | free(fullSocket); 491 | return; 492 | } 493 | 494 | pid_t pid; 495 | int status; 496 | switch (pid = fork ()) { 497 | case -1: 498 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't fork to execv kwalletd", logPrefix); 499 | free(fullSocket); 500 | return; 501 | 502 | //Child fork, will contain kwalletd 503 | case 0: 504 | execute_kwallet(pamh, userInfo, toWalletPipe, fullSocket); 505 | /* Should never be reached */ 506 | break; 507 | 508 | //Parent 509 | default: 510 | waitpid(pid, &status, 0); 511 | if (status != 0) { 512 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't fork to execv kwalletd", logPrefix); 513 | return; 514 | } 515 | break; 516 | }; 517 | 518 | free(fullSocket); 519 | 520 | close(toWalletPipe[0]);//Read end of the pipe, we will only use the write 521 | if (better_write(toWalletPipe[1], kwalletKey, KWALLET_PAM_KEYSIZE) < 0) { 522 | pam_syslog(pamh, LOG_ERR, "%s: Impossible to write walletKey to walletPipe", logPrefix); 523 | return; 524 | } 525 | 526 | close(toWalletPipe[1]); 527 | } 528 | 529 | PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) 530 | { 531 | pam_syslog(pamh, LOG_DEBUG, "%s: pam_sm_open_session\n", logPrefix); 532 | 533 | if (get_env(pamh, envVar) != NULL) { 534 | pam_syslog(pamh, LOG_INFO, "%s: we were already executed", logPrefix); 535 | return PAM_SUCCESS; 536 | } 537 | 538 | parseArguments(argc, argv); 539 | 540 | if (!force_run && !is_graphical_session(pamh)) { 541 | pam_syslog(pamh, LOG_INFO, "%s: not a graphical session, skipping. Use force_run parameter to ignore this.", logPrefix); 542 | return PAM_IGNORE; 543 | } 544 | 545 | //Fetch the user, needed to get user information 546 | const char *username; 547 | int result = pam_get_user(pamh, &username, NULL); 548 | if (result != PAM_SUCCESS) { 549 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't get username %s", 550 | logPrefix, pam_strerror(pamh, result)); 551 | return PAM_IGNORE;//Since we are not an essential module, just make pam ignore us 552 | } 553 | 554 | struct passwd *userInfo; 555 | userInfo = getpwnam(username); 556 | if (!userInfo) { 557 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't get user info (passwd) info", logPrefix); 558 | return PAM_IGNORE; 559 | } 560 | 561 | if (userInfo->pw_uid == 0) { 562 | pam_syslog(pamh, LOG_DEBUG, "%s: Refusing to do anything for the root user", logPrefix); 563 | return PAM_IGNORE; 564 | } 565 | 566 | char *password; 567 | result = pam_get_data(pamh, kwalletPamDataKey, (const void **)&password); 568 | 569 | if (result != PAM_SUCCESS) { 570 | pam_syslog(pamh, LOG_INFO, "%s: open_session called without %s", logPrefix, kwalletPamDataKey); 571 | return PAM_IGNORE; 572 | } 573 | 574 | char *key = malloc(KWALLET_PAM_KEYSIZE); 575 | if (!key || kwallet_hash(pamh, password, userInfo, key) != 0) { 576 | free(key); 577 | pam_syslog(pamh, LOG_ERR, "%s: Fail into creating the hash", logPrefix); 578 | return PAM_IGNORE; 579 | } 580 | 581 | start_kwallet(pamh, userInfo, key); 582 | 583 | return PAM_SUCCESS; 584 | } 585 | 586 | PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) 587 | { 588 | pam_syslog(pamh, LOG_DEBUG, "%s: pam_sm_close_session", logPrefix); 589 | return PAM_SUCCESS; 590 | } 591 | 592 | PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) 593 | { 594 | pam_syslog(pamh, LOG_DEBUG, "%s: pam_sm_setcred", logPrefix); 595 | return PAM_SUCCESS; 596 | } 597 | 598 | 599 | PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) 600 | { 601 | pam_syslog(pamh, LOG_DEBUG, "%s: pam_sm_chauthtok", logPrefix); 602 | return PAM_SUCCESS; 603 | } 604 | 605 | static int mkpath(char *path) 606 | { 607 | struct stat sb; 608 | char *slash; 609 | int done = 0; 610 | 611 | slash = path; 612 | 613 | while (!done) { 614 | slash += strspn(slash, "/"); 615 | slash += strcspn(slash, "/"); 616 | 617 | done = (*slash == '\0'); 618 | *slash = '\0'; 619 | 620 | if (stat(path, &sb)) { 621 | if (errno != ENOENT || (mkdir(path, 0777) && 622 | errno != EEXIST)) { 623 | syslog(LOG_ERR, "%s: Couldn't create directory: %s because: %d-%s", logPrefix, path, errno, strerror(errno)); 624 | return (-1); 625 | } 626 | } else if (!S_ISDIR(sb.st_mode)) { 627 | return (-1); 628 | } 629 | 630 | *slash = '/'; 631 | } 632 | 633 | return (0); 634 | } 635 | 636 | static void createNewSalt(pam_handle_t *pamh, const char *path, struct passwd *userInfo) 637 | { 638 | const pid_t pid = fork(); 639 | if (pid == -1) { 640 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't fork to create salt file", logPrefix); 641 | } else if (pid == 0) { 642 | // Child process 643 | if (drop_privileges(userInfo) < 0) { 644 | syslog(LOG_ERR, "%s: could not set gid/uid/euid/egit for salt file creation", logPrefix); 645 | exit(-1); 646 | } 647 | 648 | // Don't re-create it if it already exists 649 | struct stat info; 650 | if (stat(path, &info) == 0 && 651 | info.st_size != 0 && 652 | S_ISREG(info.st_mode)) { 653 | exit(0); 654 | } 655 | 656 | unlink(path);//in case the file already exists 657 | 658 | char *dir = strdup(path); 659 | dir[strlen(dir) - 14] = '\0';//remove kdewallet.salt 660 | mkpath(dir); //create the path in case it does not exists 661 | free(dir); 662 | 663 | char *salt = gcry_random_bytes(KWALLET_PAM_SALTSIZE, GCRY_STRONG_RANDOM); 664 | const int fd = open(path, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0600); 665 | 666 | //If the file can't be created 667 | if (fd == -1) { 668 | syslog(LOG_ERR, "%s: Couldn't open file: %s because: %d-%s", logPrefix, path, errno, strerror(errno)); 669 | exit(-2); 670 | } 671 | 672 | const ssize_t wlen = write(fd, salt, KWALLET_PAM_SALTSIZE); 673 | close(fd); 674 | if (wlen != KWALLET_PAM_SALTSIZE) { 675 | syslog(LOG_ERR, "%s: Short write to file: %s", logPrefix, path); 676 | unlink(path); 677 | exit(-2); 678 | } 679 | 680 | exit(0); // success 681 | } else { 682 | // pam process, just wait for child to finish 683 | int status; 684 | waitpid(pid, &status, 0); 685 | if (status != 0) { 686 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't create salt file", logPrefix); 687 | } 688 | } 689 | } 690 | 691 | static int readSaltFile(pam_handle_t *pamh, char *path, struct passwd *userInfo, char *saltOut) 692 | { 693 | int readSaltPipe[2]; 694 | if (pipe(readSaltPipe) < 0) { 695 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't create read salt pipes", logPrefix); 696 | return 0; 697 | } 698 | 699 | const pid_t pid = fork(); 700 | if (pid == -1) { 701 | syslog(LOG_ERR, "%s: Couldn't fork to read salt file", logPrefix); 702 | close(readSaltPipe[0]); 703 | close(readSaltPipe[1]); 704 | return 0; 705 | } else if (pid == 0) { 706 | // Child process 707 | close(readSaltPipe[0]); // we won't be reading from the pipe 708 | if (drop_privileges(userInfo) < 0) { 709 | syslog(LOG_ERR, "%s: could not set gid/uid/euid/egit for salt file reading", logPrefix); 710 | free(path); 711 | close(readSaltPipe[1]); 712 | exit(-1); 713 | } 714 | 715 | struct stat info; 716 | if (stat(path, &info) != 0 || info.st_size == 0 || !S_ISREG(info.st_mode)) { 717 | syslog(LOG_ERR, "%s: Failed to ensure %s looks like a salt file", logPrefix, path); 718 | free(path); 719 | close(readSaltPipe[1]); 720 | exit(-1); 721 | } 722 | 723 | const int fd = open(path, O_RDONLY | O_CLOEXEC); 724 | if (fd == -1) { 725 | syslog(LOG_ERR, "%s: Couldn't open file: %s because: %d-%s", logPrefix, path, errno, strerror(errno)); 726 | free(path); 727 | close(readSaltPipe[1]); 728 | exit(-1); 729 | } 730 | free(path); 731 | char salt[KWALLET_PAM_SALTSIZE] = {}; 732 | const ssize_t bytesRead = read(fd, salt, KWALLET_PAM_SALTSIZE); 733 | close(fd); 734 | if (bytesRead != KWALLET_PAM_SALTSIZE) { 735 | syslog(LOG_ERR, "%s: Couldn't read the full salt file contents from file. %zd:%d", logPrefix, bytesRead, KWALLET_PAM_SALTSIZE); 736 | exit(-1); 737 | } 738 | 739 | const ssize_t written = better_write(readSaltPipe[1], salt, KWALLET_PAM_SALTSIZE); 740 | 741 | close(readSaltPipe[1]); 742 | if (written != KWALLET_PAM_SALTSIZE) { 743 | syslog(LOG_ERR, "%s: Couldn't write the full salt file contents to pipe", logPrefix); 744 | exit(-1); 745 | } 746 | 747 | exit(0); 748 | } 749 | 750 | close(readSaltPipe[1]); // we won't be writing from the pipe 751 | 752 | // pam process, just wait for child to finish 753 | int status; 754 | waitpid(pid, &status, 0); 755 | int success = 1; 756 | if (status == 0) { 757 | const ssize_t readBytes = read(readSaltPipe[0], saltOut, KWALLET_PAM_SALTSIZE); 758 | if (readBytes != KWALLET_PAM_SALTSIZE) { 759 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't read the full salt file contents from pipe", logPrefix); 760 | success = 0; 761 | } 762 | } else { 763 | pam_syslog(pamh, LOG_ERR, "%s: Couldn't read salt file", logPrefix); 764 | success = 0; 765 | } 766 | 767 | close(readSaltPipe[0]); 768 | 769 | return success; 770 | } 771 | 772 | int kwallet_hash(pam_handle_t *pamh, const char *passphrase, struct passwd *userInfo, char *key) 773 | { 774 | if (!gcry_check_version("1.5.0")) { 775 | syslog(LOG_ERR, "%s-kwalletd: libcrypt version is too old", logPrefix); 776 | return 1; 777 | } 778 | 779 | struct stat info; 780 | if (stat(userInfo->pw_dir, &info) != 0 || !S_ISDIR(info.st_mode)) { 781 | syslog(LOG_ERR, "%s-kwalletd: user home folder does not exist", logPrefix); 782 | return 1; 783 | } 784 | 785 | const char *fixpath = "kwalletd/kdewallet.salt"; 786 | size_t pathSize = strlen(userInfo->pw_dir) + strlen(kdehome) + strlen(fixpath) + 3;//3 == /, / and \0 787 | char *path = (char*) malloc(pathSize); 788 | sprintf(path, "%s/%s/%s", userInfo->pw_dir, kdehome, fixpath); 789 | 790 | createNewSalt(pamh, path, userInfo); 791 | 792 | char salt[KWALLET_PAM_SALTSIZE] = {}; 793 | const int readSaltSuccess = readSaltFile(pamh, path, userInfo, salt); 794 | free(path); 795 | if (!readSaltSuccess) { 796 | syslog(LOG_ERR, "%s-kwalletd: Couldn't create or read the salt file", logPrefix); 797 | return 1; 798 | } 799 | 800 | gcry_error_t error; 801 | 802 | /* We cannot call GCRYCTL_INIT_SECMEM as it drops privileges if getuid() != geteuid(). 803 | * PAM modules are in many cases executed through setuid binaries, which this call 804 | * would break. 805 | * It was never effective anyway as neither key nor passphrase are in secure memory, 806 | * which is a prerequisite for secure operation... 807 | error = gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0); 808 | if (error != 0) { 809 | free(salt); 810 | syslog(LOG_ERR, "%s-kwalletd: Can't get secure memory: %d", logPrefix, error); 811 | return 1; 812 | } 813 | */ 814 | 815 | gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); 816 | 817 | error = gcry_kdf_derive(passphrase, strlen(passphrase), 818 | GCRY_KDF_PBKDF2, GCRY_MD_SHA512, 819 | salt, KWALLET_PAM_SALTSIZE, 820 | KWALLET_PAM_ITERATIONS,KWALLET_PAM_KEYSIZE, key); 821 | 822 | return (int) error; // gcry_kdf_derive returns 0 on success 823 | } 824 | --------------------------------------------------------------------------------