1 /*
2   KeePass Password Safe - The Open-Source Password Manager
3   Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 
20 using System;
21 using System.Collections.Generic;
22 using System.Diagnostics;
23 using System.Media;
24 using System.Text;
25 using System.Threading;
26 using System.Windows.Forms;
27 
28 using KeePass.Native;
29 using KeePass.Resources;
30 using KeePass.Util.SendInputExt;
31 
32 using KeePassLib.Utility;
33 
34 using NativeLib = KeePassLib.Native.NativeLib;
35 
36 namespace KeePass.Util
37 {
38 	internal enum SiEventType
39 	{
40 		None = 0,
41 		Key,
42 		KeyModifier,
43 		Char,
44 		Delay,
45 		SetDefaultDelay,
46 		ClipboardCopy,
47 		AppActivate,
48 		Beep
49 	}
50 
51 	internal sealed class SiEvent
52 	{
53 		public SiEventType Type = SiEventType.None;
54 
55 		public int VKey = 0;
56 		public bool? ExtendedKey = null;
57 
58 		public Keys KeyModifier = Keys.None;
59 
60 		public char Char = char.MinValue;
61 
62 		public bool? Down = null;
63 
64 		public uint Delay = 0;
65 
66 		public string Text = null;
67 
68 #if DEBUG
69 		// For debugger display
ToString()70 		public override string ToString()
71 		{
72 			string str = Enum.GetName(typeof(SiEventType), this.Type);
73 
74 			string strSub = null;
75 			switch(this.Type)
76 			{
77 				case SiEventType.Key:
78 					strSub = this.VKey.ToString() + " " + this.ExtendedKey.ToString() +
79 						" " + this.Down.ToString();
80 					break;
81 				case SiEventType.KeyModifier:
82 					strSub = this.KeyModifier.ToString() + " " + this.Down.ToString();
83 					break;
84 				case SiEventType.Char:
85 					strSub = this.Char.ToString() + " " + this.Down.ToString();
86 					break;
87 				case SiEventType.Delay:
88 				case SiEventType.SetDefaultDelay:
89 					strSub = this.Delay.ToString();
90 					break;
91 				case SiEventType.ClipboardCopy:
92 				case SiEventType.AppActivate:
93 				case SiEventType.Beep:
94 					strSub = this.Text;
95 					break;
96 				default: break;
97 			}
98 
99 			if(!string.IsNullOrEmpty(strSub)) return (str + ": " + strSub);
100 			return str;
101 		}
102 #endif
103 	}
104 
105 	public static class SendInputEx
106 	{
107 		private static CriticalSectionEx g_csSending = new CriticalSectionEx();
108 
109 		private static int g_cCurSending = 0;
110 		public static bool IsSending
111 		{
112 			get { return (g_cCurSending != 0); }
113 		}
114 
115 		public static event EventHandler<SiEventArgs> CreateEngine;
116 
SendKeysWait(string strKeys, bool bObfuscate)117 		public static void SendKeysWait(string strKeys, bool bObfuscate)
118 		{
119 			if(strKeys == null) { Debug.Assert(false); return; }
120 
121 			List<SiEvent> l = Parse(strKeys);
122 			if(l.Count == 0) return;
123 
124 			if(bObfuscate) SiObf.Obfuscate(l);
125 
126 			FixEventSeq(l);
127 
128 			ISiEngine si = null;
129 			if(SendInputEx.CreateEngine != null)
130 			{
131 				SiEventArgs ea = new SiEventArgs();
132 				SendInputEx.CreateEngine(null, ea);
133 				si = ea.Engine;
134 			}
135 			if(si == null)
136 			{
137 				if(NativeLib.IsUnix()) si = new SiEngineUnix();
138 				else si = new SiEngineWin();
139 			}
140 
141 			bool bInter = Program.Config.Integration.AutoTypeAllowInterleaved;
142 			if(!bInter)
143 			{
144 				if(!g_csSending.TryEnter()) return;
145 			}
146 
147 			Interlocked.Increment(ref g_cCurSending);
148 			try
149 			{
150 				si.Init();
151 				Send(si, l);
152 			}
153 			finally
154 			{
155 				try { si.Release(); }
156 				catch(Exception) { Debug.Assert(false); }
157 
158 				Interlocked.Decrement(ref g_cCurSending);
159 
160 				if(!bInter) g_csSending.Exit();
161 			}
162 		}
163 
Parse(string strSequence)164 		private static List<SiEvent> Parse(string strSequence)
165 		{
166 			CharStream cs = new CharStream(strSequence);
167 			List<SiEvent> l = new List<SiEvent>();
168 			string strError = KPRes.AutoTypeSequenceInvalid;
169 
170 			Keys kCurKbMods = Keys.None;
171 
172 			List<Keys> lMods = new List<Keys>();
173 			lMods.Add(Keys.None);
174 
175 			while(true)
176 			{
177 				char ch = cs.ReadChar();
178 				if(ch == char.MinValue) break;
179 
180 				if((ch == '+') || (ch == '^') || (ch == '%'))
181 				{
182 					if(lMods.Count == 0) { Debug.Assert(false); break; }
183 					else if(ch == '+') lMods[lMods.Count - 1] |= Keys.Shift;
184 					else if(ch == '^') lMods[lMods.Count - 1] |= Keys.Control;
185 					else if(ch == '%') lMods[lMods.Count - 1] |= Keys.Alt;
186 					else { Debug.Assert(false); }
187 
188 					continue;
189 				}
190 				else if(ch == '(')
191 				{
192 					lMods.Add(Keys.None);
193 					continue;
194 				}
195 				else if(ch == ')')
196 				{
197 					if(lMods.Count >= 2)
198 					{
199 						lMods.RemoveAt(lMods.Count - 1);
200 						lMods[lMods.Count - 1] = Keys.None;
201 					}
202 					else throw new FormatException(strError);
203 
204 					continue;
205 				}
206 
207 				Keys kEffMods = Keys.None;
208 				foreach(Keys k in lMods) kEffMods |= k;
209 
210 				EnsureKeyModifiers(kEffMods, ref kCurKbMods, l);
211 
212 				if(ch == '{')
213 				{
214 					List<SiEvent> lSub = ParseSpecial(cs);
215 					if(lSub == null) throw new FormatException(strError);
216 
217 					l.AddRange(lSub);
218 				}
219 				else if(ch == '}')
220 					throw new FormatException(strError);
221 				else if(ch == '~')
222 				{
223 					SiEvent si = new SiEvent();
224 					si.Type = SiEventType.Key;
225 					si.VKey = (int)Keys.Enter;
226 
227 					l.Add(si);
228 				}
229 				else
230 				{
231 					SiEvent si = new SiEvent();
232 					si.Type = SiEventType.Char;
233 					si.Char = ch;
234 
235 					l.Add(si);
236 				}
237 
238 				lMods[lMods.Count - 1] = Keys.None;
239 			}
240 
241 			EnsureKeyModifiers(Keys.None, ref kCurKbMods, l);
242 
243 			return l;
244 		}
245 
EnsureKeyModifiers(Keys kReqMods, ref Keys kCurKbMods, List<SiEvent> l)246 		private static void EnsureKeyModifiers(Keys kReqMods, ref Keys kCurKbMods,
247 			List<SiEvent> l)
248 		{
249 			if(kReqMods == kCurKbMods) return;
250 
251 			if((kReqMods & Keys.Shift) != (kCurKbMods & Keys.Shift))
252 			{
253 				SiEvent si = new SiEvent();
254 				si.Type = SiEventType.KeyModifier;
255 				si.KeyModifier = Keys.Shift;
256 				si.Down = ((kReqMods & Keys.Shift) != Keys.None);
257 
258 				l.Add(si);
259 			}
260 
261 			if((kReqMods & Keys.Control) != (kCurKbMods & Keys.Control))
262 			{
263 				SiEvent si = new SiEvent();
264 				si.Type = SiEventType.KeyModifier;
265 				si.KeyModifier = Keys.Control;
266 				si.Down = ((kReqMods & Keys.Control) != Keys.None);
267 
268 				l.Add(si);
269 			}
270 
271 			if((kReqMods & Keys.Alt) != (kCurKbMods & Keys.Alt))
272 			{
273 				SiEvent si = new SiEvent();
274 				si.Type = SiEventType.KeyModifier;
275 				si.KeyModifier = Keys.Alt;
276 				si.Down = ((kReqMods & Keys.Alt) != Keys.None);
277 
278 				l.Add(si);
279 			}
280 
281 			kCurKbMods = kReqMods;
282 		}
283 
ParseSpecial(CharStream cs)284 		private static List<SiEvent> ParseSpecial(CharStream cs)
285 		{
286 			// Skip leading white space
287 			while(true)
288 			{
289 				char ch = cs.PeekChar();
290 				if(ch == char.MinValue) { Debug.Assert(false); return null; }
291 
292 				if(!char.IsWhiteSpace(ch)) break;
293 				cs.ReadChar();
294 			}
295 
296 			// First char is *always* part of the name (support for "{{}", etc.)
297 			char chFirst = cs.ReadChar();
298 			if(chFirst == char.MinValue) { Debug.Assert(false); return null; }
299 
300 			int iPart = 0;
301 			StringBuilder sbName = new StringBuilder(), sbParams =
302 				new StringBuilder();
303 			sbName.Append(chFirst);
304 
305 			while(true)
306 			{
307 				char ch = cs.ReadChar();
308 				if(ch == char.MinValue) { Debug.Assert(false); return null; }
309 				if(ch == '}') break;
310 
311 				if(iPart == 0)
312 				{
313 					if(char.IsWhiteSpace(ch)) ++iPart;
314 					else sbName.Append(ch);
315 				}
316 				else sbParams.Append(ch);
317 			}
318 
319 			string strName = sbName.ToString();
320 			string strParams = sbParams.ToString().Trim();
321 
322 			uint? ouParam = null;
323 			if(strParams.Length > 0)
324 			{
325 				uint uParamTry;
326 				if(uint.TryParse(strParams, out uParamTry)) ouParam = uParamTry;
327 			}
328 
329 			List<SiEvent> l = new List<SiEvent>();
330 
331 			if(strName.Equals("DELAY", StrUtil.CaseIgnoreCmp))
332 			{
333 				if(!ouParam.HasValue) { Debug.Assert(false); return null; }
334 
335 				SiEvent si = new SiEvent();
336 				si.Type = SiEventType.Delay;
337 				si.Delay = ouParam.Value;
338 
339 				l.Add(si);
340 				return l;
341 			}
342 			if(strName.StartsWith("DELAY=", StrUtil.CaseIgnoreCmp))
343 			{
344 				SiEvent si = new SiEvent();
345 				si.Type = SiEventType.SetDefaultDelay;
346 
347 				string strDelay = strName.Substring(6).Trim();
348 				uint uDelay;
349 				if(uint.TryParse(strDelay, out uDelay))
350 					si.Delay = uDelay;
351 				else { Debug.Assert(false); return null; }
352 
353 				l.Add(si);
354 				return l;
355 			}
356 			if(strName.Equals("VKEY", StrUtil.CaseIgnoreCmp) ||
357 				strName.Equals("VKEY-NX", StrUtil.CaseIgnoreCmp) ||
358 				strName.Equals("VKEY-EX", StrUtil.CaseIgnoreCmp))
359 			{
360 				SiEvent si = CreateVKeyEvent(strParams);
361 				if(si == null) { Debug.Assert(false); return null; }
362 
363 				// VKEY-NX and VKEY-EX are supported for backward compatibility;
364 				// new syntax: {VKEY K N} and {VKEY K E}
365 				if(strName.EndsWith("-NX", StrUtil.CaseIgnoreCmp))
366 					si.ExtendedKey = false;
367 				else if(strName.EndsWith("-EX", StrUtil.CaseIgnoreCmp))
368 					si.ExtendedKey = true;
369 
370 				l.Add(si);
371 				return l;
372 			}
373 			if(strName.Equals("APPACTIVATE", StrUtil.CaseIgnoreCmp))
374 			{
375 				SiEvent si = new SiEvent();
376 				si.Type = SiEventType.AppActivate;
377 				si.Text = strParams;
378 
379 				l.Add(si);
380 				return l;
381 			}
382 			if(strName.Equals("BEEP", StrUtil.CaseIgnoreCmp))
383 			{
384 				SiEvent si = new SiEvent();
385 				si.Type = SiEventType.Beep;
386 				si.Text = strParams;
387 
388 				l.Add(si);
389 				return l;
390 			}
391 
392 			SiCode siCode = SiCodes.Get(strName);
393 
394 			SiEvent siTmpl = new SiEvent();
395 			if(siCode != null)
396 			{
397 				siTmpl.Type = SiEventType.Key;
398 				siTmpl.VKey = siCode.VKey;
399 				siTmpl.ExtendedKey = siCode.ExtKey;
400 			}
401 			else if(strName.Length == 1)
402 			{
403 				siTmpl.Type = SiEventType.Char;
404 				siTmpl.Char = strName[0];
405 			}
406 			else
407 			{
408 				throw new FormatException(KPRes.AutoTypeUnknownPlaceholder +
409 					MessageService.NewLine + @"{" + strName + @"}");
410 			}
411 
412 			uint uRepeat = ouParam.GetValueOrDefault(1);
413 			for(uint u = 0; u < uRepeat; ++u)
414 			{
415 				SiEvent si = new SiEvent();
416 				si.Type = siTmpl.Type;
417 				si.VKey = siTmpl.VKey;
418 				si.ExtendedKey = siTmpl.ExtendedKey;
419 				si.Char = siTmpl.Char;
420 
421 				l.Add(si);
422 			}
423 
424 			return l;
425 		}
426 
FixEventSeq(List<SiEvent> l)427 		private static void FixEventSeq(List<SiEvent> l)
428 		{
429 			// Convert chars to keys
430 			// Keys kMod = Keys.None;
431 			for(int i = 0; i < l.Count; ++i)
432 			{
433 				SiEvent si = l[i];
434 				SiEventType t = si.Type;
435 
436 				// if(t == SiEventType.KeyModifier)
437 				// {
438 				//	if(!si.Down.HasValue) { Debug.Assert(false); continue; }
439 				//	if(si.Down.Value)
440 				//	{
441 				//		Debug.Assert((kMod & si.KeyModifier) == Keys.None);
442 				//		kMod |= si.KeyModifier;
443 				//	}
444 				//	else
445 				//	{
446 				//		Debug.Assert((kMod & si.KeyModifier) == si.KeyModifier);
447 				//		kMod &= ~si.KeyModifier;
448 				//	}
449 				// }
450 				if(t == SiEventType.Char)
451 				{
452 					// bool bLightConv = (kMod == Keys.None);
453 					int iVKey = SiCodes.CharToVKey(si.Char, true);
454 					if(iVKey > 0)
455 					{
456 						si.Type = SiEventType.Key;
457 						si.VKey = iVKey;
458 					}
459 				}
460 			}
461 		}
462 
Send(ISiEngine siEngine, List<SiEvent> l)463 		private static void Send(ISiEngine siEngine, List<SiEvent> l)
464 		{
465 			bool bHasClipOp = l.Exists(SendInputEx.IsClipboardOp);
466 			ClipboardEventChainBlocker cev = null;
467 			ClipboardContents cnt = null;
468 			if(bHasClipOp)
469 			{
470 				cev = new ClipboardEventChainBlocker();
471 				cnt = new ClipboardContents(true, true);
472 			}
473 
474 			try { SendPriv(siEngine, l); }
475 			finally
476 			{
477 				if(bHasClipOp)
478 				{
479 					ClipboardUtil.Clear();
480 					cnt.SetData();
481 					cev.Dispose();
482 				}
483 			}
484 		}
485 
IsClipboardOp(SiEvent si)486 		private static bool IsClipboardOp(SiEvent si)
487 		{
488 			if(si == null) { Debug.Assert(false); return false; }
489 			return (si.Type == SiEventType.ClipboardCopy);
490 		}
491 
SendPriv(ISiEngine siEngine, List<SiEvent> l)492 		private static void SendPriv(ISiEngine siEngine, List<SiEvent> l)
493 		{
494 			// For 2000 alphanumeric characters:
495 			// * KeePass 1.26: 0:31 min
496 			// * KeePass 2.24: 1:58 min
497 			// * New engine of KeePass 2.25 with default delay DD:
498 			//   * DD =  1: 0:31 min
499 			//   * DD = 31: 1:03 min
500 			//   * DD = 32: 1:34 min
501 			//   * DD = 33: 1:34 min
502 			//   * DD = 43: 1:34 min
503 			//   * DD = 46: 1:34 min
504 			//   * DD = 47: 2:05 min
505 			//   * DD = 49: 2:05 min
506 			//   * DD = 59: 2:05 min
507 			uint uDefaultDelay = 33; // Slice boundary + 1
508 
509 			// Induced by SiEngineWin.TrySendCharByKeypresses
510 			uDefaultDelay += 2;
511 
512 			int iDefOvr = Program.Config.Integration.AutoTypeInterKeyDelay;
513 			if(iDefOvr >= 0)
514 			{
515 				if(iDefOvr == 0) iDefOvr = 1; // 1 ms is minimum
516 				uDefaultDelay = (uint)iDefOvr;
517 			}
518 
519 			bool bFirstInput = true;
520 			foreach(SiEvent si in l)
521 			{
522 				// Also delay key modifiers, as a workaround for applications
523 				// with broken time-dependent message processing;
524 				// https://sourceforge.net/p/keepass/bugs/1213/
525 				if((si.Type == SiEventType.Key) || (si.Type == SiEventType.Char) ||
526 					(si.Type == SiEventType.KeyModifier))
527 				{
528 					if(!bFirstInput)
529 						siEngine.Delay(uDefaultDelay);
530 
531 					bFirstInput = false;
532 				}
533 
534 				switch(si.Type)
535 				{
536 					case SiEventType.Key:
537 						siEngine.SendKey(si.VKey, si.ExtendedKey, si.Down);
538 						break;
539 
540 					case SiEventType.KeyModifier:
541 						if(si.Down.HasValue)
542 							siEngine.SetKeyModifier(si.KeyModifier, si.Down.Value);
543 						else { Debug.Assert(false); }
544 						break;
545 
546 					case SiEventType.Char:
547 						siEngine.SendChar(si.Char, si.Down);
548 						break;
549 
550 					case SiEventType.Delay:
551 						siEngine.Delay(si.Delay);
552 						break;
553 
554 					case SiEventType.SetDefaultDelay:
555 						uDefaultDelay = si.Delay;
556 						break;
557 
558 					case SiEventType.ClipboardCopy:
559 						if(!string.IsNullOrEmpty(si.Text))
560 							ClipboardUtil.Copy(si.Text, false, false, null,
561 								null, IntPtr.Zero);
562 						else if(si.Text != null)
563 							ClipboardUtil.Clear();
564 						break;
565 
566 					case SiEventType.AppActivate:
567 						AppActivate(si);
568 						break;
569 
570 					case SiEventType.Beep:
571 						Beep(si);
572 						break;
573 
574 					default:
575 						Debug.Assert(false);
576 						break;
577 				}
578 
579 				// Extra delay after tabs
580 				if(((si.Type == SiEventType.Key) && (si.VKey == (int)Keys.Tab)) ||
581 					((si.Type == SiEventType.Char) && (si.Char == '\t')))
582 				{
583 					if(uDefaultDelay < 100)
584 						siEngine.Delay(uDefaultDelay);
585 				}
586 			}
587 		}
588 
AppActivate(SiEvent si)589 		private static void AppActivate(SiEvent si)
590 		{
591 			try
592 			{
593 				if(string.IsNullOrEmpty(si.Text)) return;
594 
595 				IntPtr h = NativeMethods.FindWindow(si.Text);
596 				if(h != IntPtr.Zero)
597 					NativeMethods.EnsureForegroundWindow(h);
598 			}
599 			catch(Exception) { Debug.Assert(false); }
600 		}
601 
Beep(SiEvent si)602 		private static void Beep(SiEvent si)
603 		{
604 			try
605 			{
606 				string str = si.Text;
607 				if(string.IsNullOrEmpty(str))
608 				{
609 					SystemSounds.Beep.Play();
610 					return;
611 				}
612 
613 				string[] v = str.Split(new char[] { ' ', '\t' },
614 					StringSplitOptions.RemoveEmptyEntries);
615 
616 				int f = 800, d = 200; // Defaults of Console.Beep()
617 				if(v.Length >= 1) int.TryParse(v[0], out f);
618 				if(v.Length >= 2) int.TryParse(v[1], out d);
619 
620 				f = Math.Min(Math.Max(f, 37), 32767);
621 				if(d <= 0) return;
622 
623 				Console.Beep(f, d); // Throws on a server
624 			}
625 			catch(Exception) { Debug.Assert(false); }
626 		}
627 
CreateVKeyEvent(string strParams)628 		private static SiEvent CreateVKeyEvent(string strParams)
629 		{
630 			string[] v = (strParams ?? string.Empty).Trim().Split(
631 				new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
632 			if((v == null) || (v.Length < 1)) { Debug.Assert(false); return null; }
633 
634 			SiEvent si = new SiEvent();
635 			si.Type = SiEventType.Key;
636 
637 			int k;
638 			if(!StrUtil.TryParseInt(v[0], out k)) { Debug.Assert(false); return null; }
639 			if(k < 0) { Debug.Assert(false); return null; }
640 			si.VKey = k;
641 
642 			for(int i = 1; i < v.Length; ++i)
643 			{
644 				string strParam = v[i];
645 				if(string.IsNullOrEmpty(strParam)) { Debug.Assert(false); continue; }
646 
647 				if(strParam.IndexOf('=') < 0)
648 				{
649 					bool bExt = (strParam.IndexOf('E') >= 0);
650 					bool bNonExt = (strParam.IndexOf('N') >= 0);
651 					if(bExt && !bNonExt) si.ExtendedKey = true;
652 					if(!bExt && bNonExt) si.ExtendedKey = false;
653 					// The default is null => automatic decision
654 
655 					bool bDown = (strParam.IndexOf('D') >= 0);
656 					bool bUp = (strParam.IndexOf('U') >= 0);
657 					if(bDown && !bUp) si.Down = true;
658 					if(!bDown && bUp) si.Down = false;
659 					// The default is null => down and up
660 				}
661 
662 				// Named parameters with values could be implemented like
663 				// {VKEY X ED R=5 DA=100}, and parameters without a '='
664 				// could be treated as flags (so {VKEY X ED} = {VKEY X E D})
665 			}
666 
667 			return si;
668 		}
669 	}
670 }
671