source: osm/applications/editors/josm/plugins/native-password-manager/src/org/netbeans/modules/keyring/kde/KWalletProvider.java@ 35665

Last change on this file since 35665 was 35665, checked in by Don-vip, 4 years ago

update to latest JNA

File size: 9.3 KB
Line 
1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
5 *
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
8 *
9 * The contents of this file are subject to the terms of either the GNU
10 * General Public License Version 2 only ("GPL") or the Common
11 * Development and Distribution License("CDDL") (collectively, the
12 * "License"). You may not use this file except in compliance with the
13 * License. You can obtain a copy of the License at
14 * http://www.netbeans.org/cddl-gplv2.html
15 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16 * specific language governing permissions and limitations under the
17 * License. When distributing the software, include this License Header
18 * Notice in each file and include the License file at
19 * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
20 * particular file as subject to the "Classpath" exception as provided
21 * by Oracle in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the
23 * License Header, with the fields enclosed by brackets [] replaced by
24 * your own identifying information:
25 * "Portions Copyrighted [year] [name of copyright owner]"
26 *
27 * If you wish your version of this file to be governed by only the CDDL
28 * or only the GPL Version 2, indicate your decision by adding
29 * "[Contributor] elects to include this software in this distribution
30 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31 * single choice of license, a recipient has the option to distribute
32 * your version of this file under either the CDDL, the GPL Version 2 or
33 * to extend the choice of license to its licensees as provided above.
34 * However, if you add GPL Version 2 code and therefore, elected the GPL
35 * Version 2 license, then the option applies only if the new code is
36 * made subject to such option by the copyright holder.
37 *
38 * Contributor(s):
39 *
40 * Portions Copyrighted 2010 Sun Microsystems, Inc.
41 */
42
43package org.netbeans.modules.keyring.kde;
44
45import java.io.BufferedReader;
46import java.io.IOException;
47import java.io.InputStreamReader;
48import java.nio.charset.StandardCharsets;
49import java.util.Arrays;
50import java.util.logging.Level;
51import java.util.logging.Logger;
52
53import org.netbeans.spi.keyring.KeyringProvider;
54
55/**
56 * JNA wrapper for certain functions from KDE Wallet API.
57 * @author psychollek, ynov
58 */
59public class KWalletProvider implements KeyringProvider {
60
61 private static final Logger logger = Logger.getLogger(KWalletProvider.class.getName());
62 private char[] handler = "0".toCharArray();
63 private boolean timeoutHappened = false;
64 private char[] defaultLocalWallet = "kdewallet".toCharArray();
65
66 @Override
67 public boolean enabled(){
68 if (Boolean.getBoolean("netbeans.keyring.no.native")) {
69 logger.fine("native keyring integration disabled");
70 return false;
71 }
72 CommandResult result = runCommand("isEnabled");
73 if(new String(result.retVal).equals("true")) {
74 return updateHandler();
75 }
76 return false;
77 }
78
79 @Override
80 public char[] read(String key){
81 if (updateHandler()){
82 CommandResult result = runCommand("readPassword", handler, getApplicationName(), key.toCharArray(), getApplicationName());
83 if (result.exitCode != 0){
84 warning("read action returned not 0 exitCode");
85 }
86 return result.retVal.length > 0 ? result.retVal : null;
87 }
88 return null;
89 //throw new KwalletException("read");
90 }
91
92 @Override
93 public void save(String key, char[] password, String description){
94 //description is forgoten ! kdewallet dosen't have any facility to store
95 //it by default and I don't want to do it by adding new fields to kwallet
96 if (updateHandler()){
97 CommandResult result = runCommand("writePassword", handler , getApplicationName()
98 , key.toCharArray(), password , getApplicationName());
99 if (result.exitCode != 0 || new String(result.retVal).equals("-1")) {
100 warning("save action failed");
101 }
102 return;
103 }
104 //throw new KwalletException("save");
105 }
106
107 @Override
108 public void delete(String key){
109 if (updateHandler()){
110 CommandResult result = runCommand("removeEntry" ,handler,
111 getApplicationName() , key.toCharArray() , getApplicationName());
112 if (result.exitCode != 0 || new String(result.retVal).equals("-1")) {
113 warning("delete action failed");
114 }
115 return;
116 }
117 //throw new KwalletException("delete");
118 }
119
120 private boolean updateHandler(){
121 if(timeoutHappened) {
122 return false;
123 }
124 handler = new String(handler).equals("")? "0".toCharArray() : handler;
125 CommandResult result = runCommand("isOpen",handler);
126 if(new String(result.retVal).equals("true")){
127 return true;
128 }
129 char[] localWallet = defaultLocalWallet;
130 result = runCommand("localWallet");
131 if(result.exitCode == 0) {
132 localWallet = result.retVal;
133 }
134
135 if(new String(localWallet).contains(".service")) {
136 //Temporary workaround for the bug in kdelibs/kdeui/util/kwallet.cpp
137 //The bug was fixed http://svn.reviewboard.kde.org/r/5885/diff/
138 //but many people currently use buggy kwallet
139 return false;
140 }
141 result = runCommand("open", localWallet , "0".toCharArray(), getApplicationName());
142 if(result.exitCode == 2) {
143 warning("time out happened while accessing KWallet");
144 //don't try to open KWallet anymore until bug https://bugs.kde.org/show_bug.cgi?id=259229 is fixed
145 timeoutHappened = true;
146 return false;
147 }
148 if(result.exitCode != 0 || new String(result.retVal).equals("-1")) {
149 warning("failed to access KWallet");
150 return false;
151 }
152 handler = result.retVal;
153 return true;
154 }
155
156
157
158 private CommandResult runCommand(String command,char[]... commandArgs) {
159 String[] argv = new String[commandArgs.length+4];
160 argv[0] = "qdbus";
161 argv[1] = "org.kde.kwalletd";
162 argv[2] = "/modules/kwalletd";
163 argv[3] = "org.kde.KWallet."+command;
164 for (int i = 0; i < commandArgs.length; i++) {
165 //unfortunatelly I cannot pass char[] to the exec in any way - so this poses a security issue with passwords in String() !
166 //TODO: find a way to avoid changing char[] into String
167 argv[i+4] = new String(commandArgs[i]);
168 }
169 Runtime rt = Runtime.getRuntime();
170 String retVal = "";
171 String errVal = "";
172 int exitCode = 0;
173 try {
174 if (logger.isLoggable(Level.FINE)) {
175 logger.log(Level.FINE, "executing {0}", Arrays.toString(argv));
176 }
177 Process pr = rt.exec(argv);
178
179 try (BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream(), StandardCharsets.UTF_8))) {
180
181 String line;
182 while((line = input.readLine()) != null) {
183 if (!retVal.equals("")){
184 retVal = retVal.concat("\n");
185 }
186 retVal = retVal.concat(line);
187 }
188 }
189 try (BufferedReader input = new BufferedReader(new InputStreamReader(pr.getErrorStream(), StandardCharsets.UTF_8))) {
190
191 String line;
192 while((line = input.readLine()) != null) {
193 if (!errVal.equals("")){
194 errVal = errVal.concat("\n");
195 }
196 errVal = errVal.concat(line);
197 }
198 }
199
200 exitCode = pr.waitFor();
201 if (logger.isLoggable(Level.FINE)) {
202 logger.log(Level.FINE, "application exit with code {0} for commandString: {1}; errVal: {2}",
203 new Object[]{exitCode, Arrays.toString(argv), errVal});
204 }
205 } catch (InterruptedException ex) {
206 logger.log(Level.FINE,
207 "exception thrown while invoking the command \""+Arrays.toString(argv)+"\"",
208 ex);
209 } catch (IOException ex) {
210 logger.log(Level.FINE,
211 "exception thrown while invoking the command \""+Arrays.toString(argv)+"\"",
212 ex);
213 }
214 return new CommandResult(exitCode, retVal.trim().toCharArray(), errVal.trim());
215 }
216
217 private char[] getApplicationName(){
218 return "JOSM".toCharArray(); // NOI18N
219 }
220
221 private void warning(String descr) {
222 logger.log(Level.WARNING, "Something went wrong: {0}", descr);
223 }
224
225 private static class CommandResult {
226 private int exitCode;
227 private char[] retVal;
228
229 public CommandResult(int exitCode, char[] retVal, String errVal) {
230 this.exitCode = exitCode;
231 this.retVal = retVal;
232 }
233 }
234
235}
Note: See TracBrowser for help on using the repository browser.