1 /*
2 * Copyright (c) 2017-2018, 2020 Paul Mattes.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the names of Paul Mattes nor the names of his contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 * b_password.c
30 * TLS password for b3270.
31 */
32
33 #include "globals.h"
34
35 #include <errno.h>
36
37 #include "actions.h"
38 #include "b_password.h"
39 #include "lazya.h"
40 #include "task.h"
41 #include "telnet.h"
42 #include "host.h"
43 #include "trace.h"
44 #include "utils.h"
45
46 /* Macros. */
47 #define PASSWORD_PASSTHRU_NAME "TlsKeyPassword"
48 #define PASSWORD_PASSTHRU_CALL PASSWORD_PASSTHRU_NAME "()"
49
50 /* Globals. */
51
52 /* Statics. */
53
54 static void password_data(task_cbh handle, const char *buf, size_t len,
55 bool success);
56 static bool password_done(task_cbh handle, bool success, bool abort);
57
58 /* Callback block for actions. */
59 static tcb_t password_cb = {
60 "password",
61 IA_PASSWORD,
62 CB_NEW_TASKQ,
63 password_data,
64 password_done,
65 NULL
66 };
67
68 static char *password_result = NULL;
69
70 /**
71 * Callback for data returned to password.
72 *
73 * @param[in] handle Callback handle
74 * @param[in] buf Buffer
75 * @param[in] len Buffer length
76 * @param[in] success True if data, false if error message
77 */
78 static void
password_data(task_cbh handle,const char * buf,size_t len,bool success)79 password_data(task_cbh handle, const char *buf, size_t len, bool success)
80 {
81 if (handle != (tcb_t *)&password_cb) {
82 vtrace("password_data: no match\n");
83 return;
84 }
85
86 Replace(password_result, xs_buffer("%.*s", (int)len, buf));
87 }
88
89 /*
90 * Timeout (asynchrous call) for password error.
91 */
92 static void
password_error(ioid_t ioid)93 password_error(ioid_t ioid)
94 {
95 connect_error("%s",
96 password_result? password_result: "Password failed");
97 Replace(password_result, NULL);
98 }
99
100 /**
101 * Callback for completion of password pass-through command.
102 *
103 * @param[in] handle Callback handle
104 * @param[in] success True if child succeeded
105 * @param[in] abort True if aborting
106 *
107 * @return True if context is complete
108 */
109 static bool
password_done(task_cbh handle,bool success,bool abort)110 password_done(task_cbh handle, bool success, bool abort)
111 {
112 if (handle != (tcb_t *)&password_cb) {
113 vtrace("password_data: no match\n");
114 return true;
115 }
116
117 if (success) {
118 net_password_continue(password_result);
119 } else {
120 vtrace("Password command failed%s%s\n",
121 password_result? ": ": "",
122 password_result? password_result: "");
123 AddTimeOut(1, password_error);
124 }
125 return true;
126 }
127
128 /**
129 * Push a password command.
130 * @return true if pass-through queued, false otherwise.
131 */
132 bool
push_password(bool again)133 push_password(bool again)
134 {
135 action_elt_t *e;
136 bool found = false;
137 char *cmd;
138
139 FOREACH_LLIST(&actions_list, e, action_elt_t *) {
140 if (!strcasecmp(e->t.name, PASSWORD_PASSTHRU_NAME)) {
141 found = true;
142 break;
143 }
144 } FOREACH_LLIST_END(&actions_list, e, action_elt_t *);
145 if (!found) {
146 return false;
147 }
148
149 /* No result yet. */
150 Replace(password_result, NULL);
151
152 /* Push a callback with a macro. */
153 cmd = lazyaf("%s(%s)", PASSWORD_PASSTHRU_NAME, again? "again": "");
154 push_cb(cmd, strlen(cmd), &password_cb, (task_cbh)&password_cb);
155 return true;
156 }
157
158 /**
159 * Return restrictions based on a passthru command name.
160 * @returns IA_NONE or IA_PASSWORD.
161 */
162 ia_t
password_ia_restrict(const char * action)163 password_ia_restrict(const char *action)
164 {
165 return strcasecmp(action, PASSWORD_PASSTHRU_NAME)? IA_NONE: IA_PASSWORD;
166 }
167