1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2018 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23
24 #include "auth_pam.h"
25
26 #include <security/pam_appl.h>
27 #include <readline/readline.h>
28 #include <readline/history.h>
29
30 #include "include/bareos.h"
31 #include "console_output.h"
32 #include "lib/bsock.h"
33 #include "lib/bsock_tcp.h"
34
35 enum class PamAuthState
36 {
37 INIT,
38 RECEIVE_MSG_TYPE,
39 RECEIVE_MSG,
40 READ_INPUT,
41 SEND_INPUT,
42 AUTH_OK
43 };
44
45 static PamAuthState state = PamAuthState::INIT;
46 static bool SetEcho(FILE* std_in, bool on);
47
48
ConsolePamAuthenticate(FILE * std_in,BareosSocket * UA_sock)49 bool ConsolePamAuthenticate(FILE* std_in, BareosSocket* UA_sock)
50 {
51 bool quit = false;
52 bool error = false;
53
54 int type;
55 btimer_t* tid = nullptr;
56 char* userinput = nullptr;
57
58 while (!error && !quit) {
59 switch (state) {
60 case PamAuthState::INIT:
61 if (tid) { StopBsockTimer(tid); }
62 tid = StartBsockTimer(UA_sock, 30);
63 if (!tid) { error = true; }
64 state = PamAuthState::RECEIVE_MSG_TYPE;
65 break;
66 case PamAuthState::RECEIVE_MSG_TYPE:
67 if (UA_sock->recv() == 1) {
68 type = UA_sock->msg[0];
69 switch (type) {
70 case PAM_PROMPT_ECHO_OFF:
71 case PAM_PROMPT_ECHO_ON:
72 SetEcho(std_in, type == PAM_PROMPT_ECHO_ON);
73 state = PamAuthState::RECEIVE_MSG;
74 break;
75 case PAM_SUCCESS:
76 if (UA_sock->recv() == 1) {
77 state = PamAuthState::AUTH_OK;
78 quit = true;
79 } else {
80 Dmsg0(100, "Error, did not receive 2nd part of a message\n");
81 error = true;
82 }
83 break;
84 default:
85 Dmsg1(100, "Error, unknown pam type %d\n", type);
86 error = true;
87 break;
88 } /* switch (type) */
89 } else {
90 error = true;
91 }
92 break;
93 case PamAuthState::RECEIVE_MSG:
94 if (UA_sock->recv() > 0) {
95 ConsoleOutput(UA_sock->msg);
96 state = PamAuthState::READ_INPUT;
97 } else {
98 error = true;
99 }
100 break;
101 case PamAuthState::READ_INPUT: {
102 userinput = readline("");
103 if (userinput) {
104 state = PamAuthState::SEND_INPUT;
105 } else {
106 error = true;
107 }
108 } break;
109 case PamAuthState::SEND_INPUT:
110 UA_sock->fsend(userinput);
111 free(userinput);
112 userinput = nullptr;
113 state = PamAuthState::INIT;
114 break;
115 default:
116 break;
117 }
118 if (UA_sock->IsStop() || UA_sock->IsError()) {
119 if (userinput) {
120 free(userinput);
121 userinput = nullptr;
122 }
123 error = true;
124 break;
125 }
126 }; /* while (!quit) */
127
128 if (tid) { StopBsockTimer(tid); }
129 SetEcho(std_in, true);
130 ConsoleOutput("\n");
131
132 return !error;
133 }
134
135 #include <termios.h>
SetEcho(FILE * std_in,bool on)136 static bool SetEcho(FILE* std_in, bool on)
137 {
138 struct termios termios_old, termios_new;
139
140 /* Turn echoing off and fail if we can’t. */
141 if (tcgetattr(fileno(std_in), &termios_old) != 0) return false;
142 termios_new = termios_old;
143 if (on) {
144 termios_new.c_lflag |= ECHO;
145 } else {
146 termios_new.c_lflag &= ~ECHO;
147 }
148 if (tcsetattr(fileno(std_in), TCSAFLUSH, &termios_new) != 0) return false;
149 return true;
150 }
151