1 /* SLiM - Simple Login Manager
2    Copyright (C) 2007 Martin Parm
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 */
9 #include <string>
10 #include <iostream>
11 #include "PAM.h"
12 
13 namespace PAM {
Exception(pam_handle_t * _pam_handle,const std::string & _func_name,int _errnum)14 	Exception::Exception(pam_handle_t* _pam_handle,
15 					const std::string& _func_name,
16 					int _errnum):
17 		errnum(_errnum),
18 		errstr(pam_strerror(_pam_handle, _errnum)),
19 		func_name(_func_name)
20 		{}
21 
~Exception(void)22 	Exception::~Exception(void){}
23 
Auth_Exception(pam_handle_t * _pam_handle,const std::string & _func_name,int _errnum)24 	Auth_Exception::Auth_Exception(pam_handle_t* _pam_handle,
25 					const std::string& _func_name,
26 					int _errnum):
27 		Exception(_pam_handle, _func_name, _errnum){}
28 
Cred_Exception(pam_handle_t * _pam_handle,const std::string & _func_name,int _errnum)29 	Cred_Exception::Cred_Exception(pam_handle_t* _pam_handle,
30 					const std::string& _func_name,
31 					int _errnum):
32 		Exception(_pam_handle, _func_name, _errnum){}
33 
_end(void)34 	int Authenticator::_end(void){
35 		int result=pam_end(pam_handle, last_result);
36 		pam_handle=0;
37 		return result;
38 	}
39 
Authenticator(conversation * conv,void * data)40 	Authenticator::Authenticator(conversation* conv, void* data):
41 		pam_handle(0),
42 		last_result(PAM_SUCCESS)
43 	{
44 		pam_conversation.conv=conv;
45 		pam_conversation.appdata_ptr=data;
46 	}
47 
~Authenticator(void)48 	Authenticator::~Authenticator(void){
49 		if (pam_handle) _end();
50 	}
51 
start(const std::string & service)52 	void Authenticator::start(const std::string& service){
53 		switch((last_result=pam_start(service.c_str(), NULL, &pam_conversation, &pam_handle))){
54 			default:
55 				throw Exception(pam_handle, "pam_start()", last_result);
56 
57 			case PAM_SUCCESS:
58 				break;
59 		}
60 		return;
61 	}
62 
end(void)63 	void Authenticator::end(void){
64 		switch((last_result=_end())){
65 			default:
66 				throw Exception(pam_handle, "pam_end()", last_result);
67 
68 			case PAM_SUCCESS:
69 				break;
70 		}
71 		return;
72 	}
73 
set_item(const Authenticator::ItemType item,const void * value)74 	void Authenticator::set_item(const Authenticator::ItemType item, const void* value){
75 		switch((last_result=pam_set_item(pam_handle, item, value))){
76 			default:
77 			_end();
78 				throw Exception(pam_handle, "pam_set_item()", last_result);
79 
80 			case PAM_SUCCESS:
81 				break;
82 		}
83 		return;
84 	}
85 
get_item(const Authenticator::ItemType item)86 	const void* Authenticator::get_item(const Authenticator::ItemType item){
87 		const void* data;
88 		switch ((last_result=pam_get_item(pam_handle, item, &data))){
89 			default:
90 			case PAM_SYSTEM_ERR:
91 #ifdef __LIBPAM_VERSION
92 			case PAM_BAD_ITEM:
93 #endif
94 				_end();
95 				throw Exception(pam_handle, "pam_get_item()", last_result);
96 
97 			case PAM_PERM_DENIED: /* The value of item was NULL */
98 			case PAM_SUCCESS:
99 				break;
100 		}
101 		return data;
102 	}
103 
104 #ifdef __LIBPAM_VERSION
fail_delay(const unsigned int micro_sec)105 	void Authenticator::fail_delay(const unsigned int micro_sec){
106 		switch((last_result=pam_fail_delay(pam_handle, micro_sec))){
107 			default:
108 				_end();
109 				throw Exception(pam_handle, "fail_delay()", last_result);
110 
111 			case PAM_SUCCESS:
112 				break;
113 		}
114 		return;
115 	}
116 #endif
117 
authenticate(void)118 	void Authenticator::authenticate(void){
119 		switch((last_result=pam_authenticate(pam_handle, 0))){
120 			default:
121 			case PAM_ABORT:
122 			case PAM_AUTHINFO_UNAVAIL:
123 				_end();
124 				throw Exception(pam_handle, "pam_authenticate()", last_result);
125 
126 			case PAM_USER_UNKNOWN:
127 			case PAM_MAXTRIES:
128 			case PAM_CRED_INSUFFICIENT:
129 			case PAM_AUTH_ERR:
130 			case PAM_CONV_ERR:
131 				throw Auth_Exception(pam_handle, "pam_authentication()", last_result);
132 
133 			case PAM_SUCCESS:
134 				break;
135 		}
136 
137 		switch((last_result=pam_acct_mgmt(pam_handle, PAM_SILENT))){
138 			/* The documentation and implementation of Linux PAM differs:
139 			   PAM_NEW_AUTHTOKEN_REQD is described in the documentation but
140 			   don't exists in the actual implementation. This issue needs
141 			   to be fixes at some point. */
142 
143 			default:
144 			/* case PAM_NEW_AUTHTOKEN_REQD: */
145 			case PAM_ACCT_EXPIRED:
146 			case PAM_USER_UNKNOWN:
147 				_end();
148 				throw Exception(pam_handle, "pam_acct_mgmt()", last_result);
149 
150 			case PAM_AUTH_ERR:
151 			case PAM_PERM_DENIED:
152 				throw Auth_Exception(pam_handle, "pam_acct_mgmt()", last_result);
153 
154 			case PAM_SUCCESS:
155 				break;
156 		};
157 		return;
158 	}
159 
open_session(void)160 	void Authenticator::open_session(void){
161 		switch((last_result=pam_setcred(pam_handle, PAM_ESTABLISH_CRED))){
162 			default:
163 			case PAM_CRED_ERR:
164 			case PAM_CRED_UNAVAIL:
165 				_end();
166 				throw Exception(pam_handle, "pam_setcred()", last_result);
167 
168 			case PAM_CRED_EXPIRED:
169 			case PAM_USER_UNKNOWN:
170 				throw Cred_Exception(pam_handle, "pam_setcred()", last_result);
171 
172 			case PAM_SUCCESS:
173 				break;
174 		}
175 
176 		switch((last_result=pam_open_session(pam_handle, 0))){
177 			/* The documentation and implementation of Linux PAM differs:
178 			   PAM_SESSION_ERROR is described in the documentation but
179 			   don't exists in the actual implementation. This issue needs
180 			   to be fixes at some point. */
181 
182 			default:
183 			/* case PAM_SESSION_ERROR: */
184 				pam_setcred(pam_handle, PAM_DELETE_CRED);
185 				_end();
186 				throw Exception(pam_handle, "pam_open_session()", last_result);
187 
188 			case PAM_SUCCESS:
189 				break;
190 		};
191 		return;
192 	}
193 
close_session(void)194 	void Authenticator::close_session(void){
195 		switch((last_result=pam_close_session(pam_handle, 0))){
196 			/* The documentation and implementation of Linux PAM differs:
197 			   PAM_SESSION_ERROR is described in the documentation but
198 			   don't exists in the actual implementation. This issue needs
199 			   to be fixes at some point. */
200 
201 			default:
202 			/* case PAM_SESSION_ERROR: */
203 				pam_setcred(pam_handle, PAM_DELETE_CRED);
204 				_end();
205 				throw Exception(pam_handle, "pam_close_session", last_result);
206 
207 			case PAM_SUCCESS:
208 				break;
209 		};
210 		switch((last_result=pam_setcred(pam_handle, PAM_DELETE_CRED))){
211 			default:
212 			case PAM_CRED_ERR:
213 			case PAM_CRED_UNAVAIL:
214 			case PAM_CRED_EXPIRED:
215 			case PAM_USER_UNKNOWN:
216 				_end();
217 				throw Exception(pam_handle, "pam_setcred()", last_result);
218 
219 			case PAM_SUCCESS:
220 				break;
221 		}
222 		return;
223 	}
224 
setenv(const std::string & key,const std::string & value)225 	void Authenticator::setenv(const std::string& key, const std::string& value){
226 		std::string name_value = key+"="+value;
227 		switch((last_result=pam_putenv(pam_handle, name_value.c_str()))){
228 			default:
229 			case PAM_PERM_DENIED:
230 			case PAM_ABORT:
231 			case PAM_BUF_ERR:
232 #ifdef __LIBPAM_VERSION
233 			case PAM_BAD_ITEM:
234 #endif
235 				_end();
236 				throw Exception(pam_handle, "pam_putenv()", last_result);
237 
238 			case PAM_SUCCESS:
239 				break;
240 		};
241 		return;
242 	}
243 
delenv(const std::string & key)244 	void Authenticator::delenv(const std::string& key){
245 		switch((last_result=pam_putenv(pam_handle, key.c_str()))){
246 			default:
247 			case PAM_PERM_DENIED:
248 			case PAM_ABORT:
249 			case PAM_BUF_ERR:
250 #ifdef __LIBPAM_VERSION
251 			case PAM_BAD_ITEM:
252 #endif
253 				_end();
254 				throw Exception(pam_handle, "pam_putenv()", last_result);
255 
256 			case PAM_SUCCESS:
257 				break;
258 		};
259 		return;
260 	}
261 
getenv(const std::string & key)262 	const char* Authenticator::getenv(const std::string& key){
263 		return pam_getenv(pam_handle, key.c_str());
264 	}
265 
getenvlist(void)266 	char** Authenticator::getenvlist(void){
267 		return pam_getenvlist(pam_handle);
268 	}
269 }
270 
operator <<(std::ostream & os,const PAM::Exception & e)271 std::ostream& operator<<( std::ostream& os, const PAM::Exception& e){
272 	os << e.func_name << ": " << e.errstr;
273 	return os;
274 }
275