1 package ch.odi.pam;
2
3
4 /**
5 * Java native interface to PAM.
6 * Loads the native libjaaspam.so.
7 *
8 * @author Ortwin Gl?ck
9 */
10 public class Pam {
11
12 private long pam_handle = 0L;
13 private PamCallback callback;
14
15 static {
16 System.loadLibrary("jaas-pam");
17 }
18
19 /**
20 *
21 * @param serviceName The service name corresponding to a PAM service in /etc/pam.d
22 * @param user The username or <code>null</code>.
23 * @param callback The callback that will get messages from PAM during authenticate.
24 */
25 public Pam(String serviceName, String user, PamCallback callback) {
26 this.callback = callback;
27
28 synchronized (Pam.class) {
29 int code = pam_start(serviceName, user);
30 if (code != PamConstants.PAM_SUCCESS) throw new PamError("PAM error code: "+ code);
31 }
32 }
33
34 /**
35 * Frees all resources associated with this objects. Calling methods on this
36 * object after a call to end() will lead to undefined results!
37 */
38 public void end() {
39
40 synchronized (Pam.class) {
41 if (pam_handle != 0L) {
42 pam_end(pam_handle);
43 pam_handle = 0L;
44 }
45 }
46 }
47
48 protected void finalize() throws Throwable {
49 end();
50 }
51
52 /**
53 * This function is used to obtain the value of the indicated item_type. Upon success returns
54 * the value of the corresponding item.
55 *
56 * @param item_type see setStringItem
57 * @return The item or <code>null</code> on error
58 */
59 public String getItem(int item_type) {
60 return pam_get_str_item(pam_handle, item_type);
61 }
62
63 /**
64 * This function is used to (re)set the value of an item.
65 *
66 * @param item_type
67 * PAM_SERVICE
68 * The service name (which identifies that PAM stack that libpam will use to authenticate the
69 * program).
70 *
71 * PAM_USER
72 * The username of the entity under who's identity service will be given. That is, following
73 * authentication, PAM_USER identifies the local entity that gets to use the service.
74 * Note, this value can be mapped from something (eg., "anonymous") to something else
75 * (eg. "guest119") by any module in the PAM stack. As such an application should consult
76 * the value of PAM_USER after each call to a pam_*() function.
77 *
78 * PAM_USER_PROMPT
79 * The string used when prompting for a user's name. The default value for this string
80 * is "Please enter username: ".
81 *
82 * PAM_TTY
83 * The terminal name: prefixed by /dev/ if it is a device file; for graphical, X-based,
84 * applications the value for this item should be the $DISPLAY variable.
85 *
86 * PAM_RUSER
87 * The requesting entity: user's username for a locally requesting user or a remote requesting
88 * user - generally an application or module will attempt to supply the value that is most
89 * strongly authenticated (a local account before a remote one. The level of trust in this
90 * value is embodied in the actual authentication stack associated with the application, so
91 * it is ultimately at the discretion of the system administrator. It should generally match
92 * the current PAM_RHOST value. That is, "PAM_RUSER@PAM_RHOST" should always identify the
93 * requesting user. In some cases, PAM_RUSER may be NULL. In such situations, it is unclear
94 * who the requesting entity is.
95 *
96 * PAM_RHOST
97 * The requesting hostname (the hostname of the machine from which the PAM_RUSER entity is
98 * requesting service). That is "PAM_RUSER@PAM_RHOST" does identify the requesting user.
99 * "luser@localhost" or "evil@evilcom.com" are valid "PAM_RUSER@PAM_RHOST" examples.
100 * In some applications, PAM_RHOST may be NULL. In such situations, it is unclear where the
101 * authentication request is originating from.
102 * @param item the value to set
103 * @return
104 * A successful call to this function returns PAM_SUCCESS. However, the application should
105 * expect at least one the following errors:
106 *
107 * PAM_SYSTEM_ERR
108 * The pam_handle_t passed as a first argument to this function was invalid.
109 *
110 * PAM_PERM_DENIED
111 * An attempt was made to replace the conversation structure with a NULL value.
112 *
113 * PAM_BUF_ERR
114 * The function ran out of memory making a copy of the item.
115 *
116 * PAM_BAD_ITEM
117 * The application attempted to set an undefined or inaccessible item.
118 */
119 public int setItem(int item_type, String item) {
120 return pam_set_str_item(pam_handle, item_type, item);
121 }
122
123 /**
124 * This function serves as an interface to the authentication mechanisms of the loaded modules.
125 *
126 * @param flags The single optional flag, which may be logically OR'd with PAM_SILENT,
127 * takes the following value, PAM_DISALLOW_NULL_AUTHTOK.
128 * @return The value returned by this function is one of the following:
129 * PAM_SUCCESS
130 * The user was authenticated
131 *
132 * PAM_AUTH_ERR
133 * The user was not authenticated
134 *
135 * PAM_CRED_INSUFFICIENT
136 * For some reason the application does not have sufficient credentials to authenticate the user.
137 *
138 * PAM_AUTHINFO_UNAVAIL
139 * The modules were not able to access the authentication information. This might be due to a
140 * network or hardware failure etc.
141 *
142 * PAM_USER_UNKNOWN
143 * The supplied username is not known to the authentication service
144 *
145 * PAM_MAXTRIES
146 * One or more of the authentication modules has reached its limit of tries authenticating
147 * the user. Do not try again.
148 *
149 * If one or more of the authentication modules fails to load, for whatever reason, this
150 * function will return PAM_ABORT.
151 */
152 public int authenticate(int flags) {
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 return pam_authenticate(pam_handle, flags);
168 }
169
170 /**
171 * The same as calling authencicate(0).
172 *
173 * @return
174 */
175 public int authenticate() {
176 return authenticate(0);
177 }
178
179 /**
180 * This function is typically called after the user has been authenticated. It establishes
181 * whether the user's account is healthy. That is to say, whether the user's account is still
182 * active and whether the user is permitted to gain access to the system at this time.
183 * @param flags Valid flags, any one of which, may be logically OR'd with PAM_SILENT, and are
184 * the same as those applicable to the flags argument of authenticate.
185 * @return The normal response from this function is PAM_SUCCESS, however, specific failures are
186 * indicated by the following error returns:
187 * PAM_AUTHTOK_EXPIRED
188 * The user is valid but their authentication token has expired. The correct response to this
189 * return-value is to require that the user satisfies the pam_chauthtok() function before
190 * obtaining service. It may not be possible for some applications to do this. In such cases,
191 * the user should be denied access until such time as they can update their password.
192 *
193 * PAM_ACCT_EXPIRED
194 * The user is no longer permitted to access the system.
195 *
196 * PAM_AUTH_ERR
197 * There was an authentication error.
198 *
199 * PAM_PERM_DENIED
200 * The user is not permitted to gain access at this time.
201 *
202 * PAM_USER_UNKNOWN
203 * The user is not known to a module's account management component.
204 */
205 public int accountManagement(int flags) {
206 return pam_acct_mgmt(pam_handle, flags);
207 }
208
209 /**
210 * The same as calling accountManagement(0).
211 * @return
212 */
213 public int accountManagement() {
214 return accountManagement(0);
215 }
216
217 /**
218 * This function is used to set the module-specific credentials of the user. It is usually
219 * called after the user has been authenticated, after the account management function has
220 * been called but before a session has been opened for the user.
221 *
222 * A credential is something that the user possesses. It is some property, such as a
223 * Kerberos ticket, or a supplementary group membership that make up the uniqueness of a
224 * given user. On a Linux (or UN*X system) the user's UID and GID's are credentials too.
225 * However, it has been decided that these properties (along with the default supplementary
226 * groups of which the user is a member) are credentials that should be set directly by the
227 * application and not by PAM.
228 *
229 * This function simply calls the pam_sm_setcred functions of each of the loaded modules.
230 * @param flags Valid flags, any one of which, may be logically OR'd with PAM_SILENT, are:
231 * PAM_ESTABLISH_CRED
232 * Set the credentials for the authentication service,
233 *
234 * PAM_DELETE_CRED
235 * Delete the credentials associated with the authentication service,
236 *
237 * PAM_REINITIALIZE_CRED
238 * Reinitialize the user credentials, and
239 *
240 * PAM_REFRESH_CRED
241 * Extend the lifetime of the user credentials.
242 *
243 * @return A successful return is signalled with PAM_SUCCESS. Errors that are especially
244 * relevant to this function are the following:
245 *
246 * PAM_CRED_UNAVAIL
247 * A module cannot retrieve the user's credentials.
248 *
249 * PAM_CRED_EXPIRED
250 * The user's credentials have expired.
251 *
252 * PAM_USER_UNKNOWN
253 * The user is not known to an authentication module.
254 *
255 * PAM_CRED_ERR
256 * A module was unable to set the credentials of the user.
257 */
258 public int setCredentials(int flags) {
259 return pam_setcred(pam_handle, flags);
260 }
261
262 /**
263 * This function is used to change the authentication token for a given user (as indicated by
264 * the state of this object).
265 *
266 * @param flags The following is a valid but optional flag which may be logically
267 * OR'd with PAM_SILENT,
268 *
269 * PAM_CHANGE_EXPIRED_AUTHTOK
270 * This argument indicates to the modules that the users authentication token (password)
271 * should only be changed if it has expired.
272 * Note, if this argument is not passed, the application requires that all authentication
273 * tokens are to be changed.
274 * @return PAM_SUCCESS is the only successful return value, valid error-returns are:
275 *
276 * PAM_AUTHTOK_ERR
277 * A module was unable to obtain the new authentication token.
278 *
279 * PAM_AUTHTOK_RECOVERY_ERR
280 * A module was unable to obtain the old authentication token.
281 *
282 * PAM_AUTHTOK_LOCK_BUSY
283 * One or more of the modules was unable to change the authentication token since it is currently locked.
284 *
285 * PAM_AUTHTOK_DISABLE_AGING
286 * Authentication token aging has been disabled for at least one of the modules.
287 *
288 * PAM_PERM_DENIED
289 * Permission denied.
290 *
291 * PAM_TRY_AGAIN
292 * Not all of the modules were in a position to update the authentication token(s). In such a case none of the user's authentication tokens are updated.
293 *
294 * PAM_USER_UNKNOWN
295 * The user is not known to the authentication token changing service.
296 */
297 public int changeAuthToken(int flags) {
298 return pam_chauthtok(pam_handle, flags);
299 }
300
301 /**
302 * This function is used to indicate that an authenticated session has begun. It is used to
303 * inform the modules that the user is currently in a session. It should be possible for the
304 * Linux-PAM library to open a session and close the same session (see section below) from
305 * different applications.
306 *
307 * Currently, this function simply calls each of the corresponding functions of the loaded
308 * modules.
309 *
310 * @param flags The only valid flag is PAM_SILENT and this is, of course, optional.
311 * @return If any of the required loaded modules are unable to open a session for the user,
312 * this function will return PAM_SESSION_ERR.
313 */
314 public int openSession(int flags) {
315 return pam_open_session(pam_handle, flags);
316 }
317
318 /**
319 * This function is used to indicate that an authenticated session has ended. It is used to
320 * inform the modules that the user is exiting a session. It should be possible for the
321 * Linux-PAM library to open a session and close the same session from different applications.
322 *
323 * This function simply calls each of the corresponding functions of the loaded modules in the
324 * same order that they were invoked with openSession.
325 *
326 * @param flags The only valid flag is PAM_SILENT and this is, of course, optional.
327 * @return If any of the required loaded modules are unable to close a session for the user,
328 * this function will return PAM_SESSION_ERR.
329 */
330 public int closeSession(int flags) {
331 return pam_close_session(pam_handle, flags);
332 }
333
334 public String getError(int errorCode) {
335 return pam_strerror(pam_handle, errorCode);
336 }
337
338
339 private int conversation(PamMessage[] messages, PamResponse[] responses) {
340 try {
341 int ret = callback.handle(messages, responses);
342 return ret;
343 } catch (Throwable th) {
344
345
346 th.printStackTrace();
347 return PamConstants.PAM_CONV_ERR;
348 }
349 }
350
351
352 private native int pam_start(String serviceName, String user);
353 private native void pam_end(long handle);
354 private native String pam_get_str_item(long handle, int item);
355 private native int pam_set_str_item(long handle, int item, String value);
356 private native int pam_authenticate(long handle, int flags);
357 private native String pam_strerror(long handle, int errnum);
358 private native int pam_acct_mgmt(long handle, int flags);
359 private native int pam_setcred(long handle, int flags);
360 private native int pam_chauthtok(long handle, int flags);
361 private native int pam_open_session(long handle, int flags);
362 private native int pam_close_session(long handle, int flags);
363 }