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