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
33 enum class PamAuthState {
34 INIT,
35 RECEIVE_MSG_TYPE,
36 RECEIVE_MSG,
37 READ_INPUT,
38 SEND_INPUT,
39 AUTH_OK
40 };
41
42 static PamAuthState state = PamAuthState::INIT;
43 static bool SetEcho(FILE *std_in, bool on);
44
45
ConsolePamAuthenticate(FILE * std_in,BareosSocket * UA_sock)46 bool ConsolePamAuthenticate(FILE *std_in, BareosSocket *UA_sock)
47 {
48 bool quit = false;
49 bool error = false;
50
51 int type;
52 btimer_t *tid = nullptr;
53 char *userinput = nullptr;
54
55 while (!error && !quit) {
56 switch(state) {
57 case PamAuthState::INIT:
58 if(tid) {
59 StopBsockTimer(tid);
60 }
61 tid = StartBsockTimer(UA_sock, 30);
62 if (!tid) {
63 error = true;
64 }
65 state = PamAuthState::RECEIVE_MSG_TYPE;
66 break;
67 case PamAuthState::RECEIVE_MSG_TYPE:
68 if (UA_sock->recv() == 1) {
69 type = UA_sock->msg[0];
70 switch (type) {
71 case PAM_PROMPT_ECHO_OFF:
72 case PAM_PROMPT_ECHO_ON:
73 SetEcho (std_in, type == PAM_PROMPT_ECHO_ON);
74 state = PamAuthState::RECEIVE_MSG;
75 break;
76 case PAM_SUCCESS:
77 if (UA_sock->recv() == 1) {
78 state = PamAuthState::AUTH_OK;
79 quit = true;
80 } else {
81 Dmsg0(100, "Error, did not receive 2nd part of a message\n");
82 error = true;
83 }
84 break;
85 default:
86 Dmsg1(100, "Error, unknown pam type %d\n", type);
87 error = true;
88 break;
89 } /* switch (type) */
90 } else {
91 error = true;
92 }
93 break;
94 case PamAuthState::RECEIVE_MSG:
95 if (UA_sock->recv() > 0) {
96 ConsoleOutput(UA_sock->msg);
97 state = PamAuthState::READ_INPUT;
98 } else {
99 error = true;
100 }
101 break;
102 case PamAuthState::READ_INPUT: {
103 userinput = readline("");
104 if (userinput) {
105 state = PamAuthState::SEND_INPUT;
106 } else {
107 error = true;
108 }
109 }
110 break;
111 case PamAuthState::SEND_INPUT:
112 UA_sock->fsend(userinput);
113 Actuallyfree(userinput);
114 userinput = nullptr;
115 state = PamAuthState::INIT;
116 break;
117 default:
118 break;
119 }
120 if (UA_sock->IsStop() || UA_sock->IsError()) {
121 if(userinput) {
122 Actuallyfree(userinput);
123 userinput = nullptr;
124 }
125 error = true;
126 break;
127 }
128 }; /* while (!quit) */
129
130 if(tid) {
131 StopBsockTimer(tid);
132 }
133 SetEcho (std_in, true);
134 ConsoleOutput("\n");
135
136 return !error;
137 }
138
139 #include <termios.h>
SetEcho(FILE * std_in,bool on)140 static bool SetEcho(FILE *std_in, bool on)
141 {
142 struct termios termios_old, termios_new;
143
144 /* Turn echoing off and fail if we can’t. */
145 if (tcgetattr (fileno (std_in), &termios_old) != 0)
146 return false;
147 termios_new = termios_old;
148 if (on) {
149 termios_new.c_lflag |= ECHO;
150 } else {
151 termios_new.c_lflag &= ~ECHO;
152 }
153 if (tcsetattr (fileno (std_in), TCSAFLUSH, &termios_new) != 0)
154 return false;
155 return true;
156 }
157