All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jvnet.libpam.PAM Maven / Gradle / Ivy

/*
 * The MIT License
 *
 * Copyright (c) 2009, Sun Microsystems, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.jvnet.libpam;

import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
import org.jvnet.libpam.impl.CLibrary.passwd;
import org.jvnet.libpam.impl.PAMLibrary.pam_conv;
import org.jvnet.libpam.impl.PAMLibrary.pam_conv.PamCallback;
import org.jvnet.libpam.impl.PAMLibrary.pam_handle_t;
import org.jvnet.libpam.impl.PAMLibrary.pam_message;
import org.jvnet.libpam.impl.PAMLibrary.pam_response;

import java.util.Set;

import static com.sun.jna.Native.POINTER_SIZE;
import static org.jvnet.libpam.impl.CLibrary.libc;
import static org.jvnet.libpam.impl.PAMLibrary.PAM_CONV_ERR;
import static org.jvnet.libpam.impl.PAMLibrary.PAM_PROMPT_ECHO_OFF;
import static org.jvnet.libpam.impl.PAMLibrary.PAM_SUCCESS;
import static org.jvnet.libpam.impl.PAMLibrary.PAM_USER;
import static org.jvnet.libpam.impl.PAMLibrary.libpam;

import java.util.logging.Logger;

/**
 * PAM authenticator.
 * 

*

* Instances are thread unsafe and non reentrant. An instace cannot be reused * to authenticate multiple users. *

*

* For an overview of PAM programming, refer to the following resources: *

*

* * @author Kohsuke Kawaguchi */ public class PAM { private static final Logger LOGGER = Logger.getLogger(PAM.class.getName()); private pam_handle_t pht; private int ret; /** * Temporarily stored to pass a value from {@link #authenticate(String, String...)} * to {@link pam_conv}. */ private String[] factors; /** * Creates a new authenticator. * * @param serviceName PAM service name. This corresponds to the service name that shows up * in the PAM configuration, */ public PAM(String serviceName) throws PAMException { pam_conv conv = new pam_conv(new PamCallback() { public int callback(int num_msg, Pointer msg, Pointer resp, Pointer _) { LOGGER.fine("pam_conv num_msg=" + num_msg); if (factors == null) return PAM_CONV_ERR; // allocates pam_response[num_msg]. the caller will free this Pointer m = libc.calloc(pam_response.SIZE, num_msg); resp.setPointer(0, m); for (int i = 0; i < factors.length; i++) { pam_message pm = new pam_message(msg.getPointer(POINTER_SIZE * i)); LOGGER.fine(pm.msg_style + ":" + pm.msg); if (pm.msg_style == PAM_PROMPT_ECHO_OFF) { pam_response r = new pam_response(m.share(pam_response.SIZE * i)); r.setResp(factors[i]); r.write(); // write to (*resp)[i] } } return PAM_SUCCESS; } }); PointerByReference phtr = new PointerByReference(); check(libpam.pam_start(serviceName, null, conv, phtr), "pam_start failed"); pht = new pam_handle_t(phtr.getValue()); } private void check(int ret, String msg) throws PAMException { this.ret = ret; if (ret != 0) { if (pht != null) throw new PAMException(msg + " : " + libpam.pam_strerror(pht, ret)); else throw new PAMException(msg); } } /** * Authenticate the user with a password. * * @return Upon a successful authentication, return information about the user. * @throws PAMException If the authentication fails. */ public UnixUser authenticate(String username, String... factors) throws PAMException { this.factors = factors; try { check(libpam.pam_set_item(pht, PAM_USER, username), "pam_set_item failed"); check(libpam.pam_authenticate(pht, 0), "pam_authenticate failed"); check(libpam.pam_setcred(pht, 0), "pam_setcred failed"); // several different error code seem to be used to represent authentication failures check(libpam.pam_acct_mgmt(pht, 0), "pam_acct_mgmt failed"); PointerByReference r = new PointerByReference(); check(libpam.pam_get_item(pht, PAM_USER, r), "pam_get_item failed"); String userName = r.getValue().getString(0); passwd pwd = libc.getpwnam(userName); if (pwd == null) throw new PAMException("Authentication succeeded but no user information is available"); return new UnixUser(userName, pwd); } finally { this.factors = null; } } /** * Returns the groups a user belongs to * * @param username * @return Set of group names * @throws PAMException * @deprecated Pointless and ugly convenience method. */ public Set getGroupsOfUser(String username) throws PAMException { return new UnixUser(username).getGroups(); } /** * After a successful authentication, call this method to obtain the effective user name. * This can be different from the user name that you passed to the {@link #authenticate(String, String)} * method. */ /** * Performs an early disposal of the object, instead of letting this GC-ed. * Since PAM may hold on to native resources that don't put pressure on Java GC, * doing this is a good idea. *

*

* This method is called by {@link #finalize()}, too, so it's not required * to call this method explicitly, however. */ public void dispose() { if (pht != null) { libpam.pam_end(pht, ret); pht = null; } } @Override protected void finalize() throws Throwable { super.finalize(); dispose(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy