!import
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is Mozilla Communicator.
15 *
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2002
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Contributor(s):
22 *
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
34 *
35 * ***** END LICENSE BLOCK ***** */
36
37 /* We expect the following arguments:
38 - pref name of LDAP directory to fetch from
39 - array with email addresses
40
41 Display modal dialog with message and stop button.
42 In onload, kick off binding to LDAP.
43 When bound, kick off the searches.
44 On finding certificates, import into permanent cert database.
45 When all searches are finished, close the dialog.
46 */
47
48 const nsIX509CertDB = Components.interfaces.nsIX509CertDB;
49 const nsX509CertDB = "@mozilla.org/security/x509certdb;1";
50 const CertAttribute = "usercertificate;binary";
51
52 var gEmailAddresses;
53 var gDirectoryPref;
54 var gLdapServerURL;
55 var gLdapConnection;
56 var gCertDB;
57 var gLdapOperation;
58 var gLogin;
59
onLoad
60 function onLoad()
61 {
62 gDirectoryPref = window.arguments[0];
63 gEmailAddresses = window.arguments[1];
64
65 if (!gEmailAddresses.length)
66 {
67 window.close();
68 return;
69 }
70
71 setTimeout(search, 1);
72 }
73
search
74 function search()
75 {
76 var prefService =
77 Components.classes["@mozilla.org/preferences-service;1"]
78 .getService(Components.interfaces.nsIPrefService);
79 var prefs = prefService.getBranch(null);
80
81 gLdapServerURL =
82 Components.classes["@mozilla.org/network/ldap-url;1"]
83 .createInstance().QueryInterface(Components.interfaces.nsILDAPURL);
84
85 // get the login to authenticate as, if there is one
86 try {
87 gLogin = prefs.getComplexValue(gDirectoryPref + ".auth.dn", Components.interfaces.nsISupportsString).data;
88 } catch (ex) {
89 // if we don't have this pref, no big deal
90 }
91
92 try {
93 gLdapServerURL.spec = prefs.getCharPref(gDirectoryPref + ".uri");
94
95 gLdapConnection = Components.classes["@mozilla.org/network/ldap-connection;1"]
96 .createInstance().QueryInterface(Components.interfaces.nsILDAPConnection);
97
98 gLdapConnection.init(gLdapServerURL, gLogin,
99 getProxyOnUIThread(new boundListener(),
100 Components.interfaces.nsILDAPMessageListener),
101 null, Components.interfaces.nsILDAPConnection.VERSION3);
102
103 } catch (ex) {
104 dump(ex);
105 dump(" exception creating ldap connection\n");
106 window.close();
107 }
108 }
109
stopFetching
110 function stopFetching()
111 {
112 if (gLdapOperation) {
113 try {
114 gLdapOperation.abandon();
115 }
116 catch (e) {
117 }
118 }
119 return true;
120 }
121
importCert
122 function importCert(ber_value)
123 {
124 if (!gCertDB) {
125 gCertDB = Components.classes[nsX509CertDB].getService(nsIX509CertDB);
126 }
127
128 var cert_length = new Object();
129 var cert_bytes = ber_value.get(cert_length);
130
131 if (cert_bytes) {
132 gCertDB.importEmailCertificate(cert_bytes, cert_length.value, null);
133 }
134 }
135
getLDAPOperation
136 function getLDAPOperation()
137 {
138 gLdapOperation = Components.classes["@mozilla.org/network/ldap-operation;1"]
139 .createInstance().QueryInterface(Components.interfaces.nsILDAPOperation);
140
141 gLdapOperation.init(gLdapConnection,
142 getProxyOnUIThread(new ldapMessageListener(),
143 Components.interfaces.nsILDAPMessageListener),
144 null);
145 }
146
getPassword
147 function getPassword()
148 {
149 // we only need a password if we are using credentials
150 if (gLogin)
151 {
152 var windowWatcherSvc = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
153 .getService(Components.interfaces.nsIWindowWatcher);
154 var authPrompter = windowWatcherSvc.getNewAuthPrompter(window.QueryInterface(Components.interfaces.nsIDOMWindow));
155 var strBundle = document.getElementById('bundle_ldap');
156 var password = { value: "" };
157
158 // nsLDAPAutocompleteSession uses asciiHost instead of host for the prompt text, I think we should be
159 // consistent.
160 if (authPrompter.promptPassword(strBundle.getString("authPromptTitle"),
161 strBundle.getFormattedString("authPromptText", [gLdapServerURL.asciiHost]),
162 gLdapServerURL.spec,
163 authPrompter.SAVE_PASSWORD_PERMANENTLY,
164 password))
165 return password.value;
166 }
167
168 return null;
169 }
170
kickOffBind
171 function kickOffBind()
172 {
173 try {
174 getLDAPOperation();
175 gLdapOperation.simpleBind(getPassword());
176 }
177 catch (e) {
178 window.close();
179 }
180 }
181
kickOffSearch
182 function kickOffSearch()
183 {
184 try {
185 var prefix1 = "";
186 var suffix1 = "";
187
188 var urlFilter = gLdapServerURL.filter;
189
190 if (urlFilter != null && urlFilter.length > 0 && urlFilter != "(objectclass=*)") {
191 if (urlFilter[0] == '(') {
192 prefix1 = "(&" + urlFilter;
193 }
194 else {
195 prefix1 = "(&(" + urlFilter + ")";
196 }
197 suffix1 = ")";
198 }
199
200 var prefix2 = "";
201 var suffix2 = "";
202
203 if (gEmailAddresses.length > 1) {
204 prefix2 = "(|";
205 suffix2 = ")";
206 }
207
208 var mailFilter = "";
209
210 for (var i = 0; i < gEmailAddresses.length; ++i) {
211 mailFilter += "(mail=" + gEmailAddresses[i] + ")";
212 }
213
214 var filter = prefix1 + prefix2 + mailFilter + suffix2 + suffix1;
215
216 var wanted_attributes = new Array();
217 wanted_attributes[0] = CertAttribute;
218
219 // Max search results =>
220 // Double number of email addresses, because each person might have
221 // multiple certificates listed. We expect at most two certificates,
222 // one for signing, one for encrypting.
223 // Maybe that number should be larger, to allow for deployments,
224 // where even more certs can be stored per user???
225
226 var maxEntriesWanted = gEmailAddresses.length * 2;
227
228 getLDAPOperation();
229 gLdapOperation.searchExt(gLdapServerURL.dn, gLdapServerURL.scope,
230 filter, 1, wanted_attributes, 0, maxEntriesWanted);
231 }
232 catch (e) {
233 window.close();
234 }
235 }
236
237
boundListener
238 function boundListener() {
239 }
240
241 boundListener.prototype.QueryInterface =
QueryInterface
242 function(iid) {
243 if (iid.equals(Components.interfaces.nsISupports) ||
244 iid.equals(Components.interfaces.nsILDAPMessageListener))
245 return this;
246
247 Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
248 return null;
249 }
250
251 boundListener.prototype.onLDAPMessage =
onLDAPMessage
252 function(aMessage) {
253 }
254
255 boundListener.prototype.onLDAPInit =
onLDAPInit
256 function(aConn, aStatus) {
257 kickOffBind();
258 }
259
260
ldapMessageListener
261 function ldapMessageListener() {
262 }
263
264 ldapMessageListener.prototype.QueryInterface =
QueryInterface
265 function(iid) {
266 if (iid.equals(Components.interfaces.nsISupports) ||
267 iid.equals(Components.interfaces.nsILDAPMessageListener))
268 return this;
269
270 Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
271 return null;
272 }
273
274 ldapMessageListener.prototype.onLDAPMessage =
onLDAPMessage
275 function(aMessage) {
276 if (Components.interfaces.nsILDAPMessage.RES_SEARCH_RESULT == aMessage.type) {
277 window.close();
278 return;
279 }
280
281 if (Components.interfaces.nsILDAPMessage.RES_BIND == aMessage.type) {
282 if (Components.interfaces.nsILDAPErrors.SUCCESS != aMessage.errorCode) {
283 window.close();
284 }
285 else {
286 kickOffSearch();
287 }
288 return;
289 }
290
291 if (Components.interfaces.nsILDAPMessage.RES_SEARCH_ENTRY == aMessage.type) {
292 var outSize = new Object();
293 try {
294 var outBinValues = aMessage.getBinaryValues(CertAttribute, outSize);
295
296 var i;
297 for (i=0; i < outSize.value; ++i) {
298 importCert(outBinValues[i]);
299 }
300 }
301 catch (e) {
302 }
303 return;
304 }
305 }
306
307 ldapMessageListener.prototype.onLDAPInit =
onLDAPInit
308 function(aConn, aStatus) {
309 }
310
311
getProxyOnUIThread
312 function getProxyOnUIThread(aObject, aInterface) {
313 var mainThread = Components.
314 classes["@mozilla.org/thread-manager;1"].
315 getService().mainThread;
316
317 var proxyMgr = Components.
318 classes["@mozilla.org/xpcomproxy;1"].
319 getService(Components.interfaces.nsIProxyObjectManager);
320
321 return proxyMgr.getProxyForObject(mainThread,
322 aInterface, aObject, 5);
323 // 5 == NS_PROXY_ALWAYS | NS_PROXY_SYNC
324 }