unix_cred.c revision ad84d946d04cc1356150710206b0b141a93e935d
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <nss_dbdefs.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <auth_attr.h>
#include <deflt.h>
#include <priv.h>
#include <secdb.h>
#include <user_attr.h>
#include <libintl.h>
#include <project.h>
#include <errno.h>
#include <alloca.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <security/pam_impl.h>
#define PROJECT "project="
/*
* unix_cred - PAM auth modules must contain both pam_sm_authenticate
* and pam_sm_setcred. Some other auth module is responsible
* for authentication (e.g., pam_unix_auth.so), this module
* only implements pam_sm_setcred so that the authentication
* can be separated without knowledge of the Solaris Unix style
* credential setting.
* Solaris Unix style credential setting includes initializing
* the audit characteristics if not already initialized and
* setting the user's default and limit privileges.
*/
/*
* unix_cred - pam_sm_authenticate
*
* Returns PAM_IGNORE.
*/
/*ARGSUSED*/
int
{
return (PAM_IGNORE);
}
/*
* Obtain a privilege set "keyname" from userattr; if none is present,
* fall back to the default, "defname".
*/
static int
void *defp)
{
char *str;
char *badp;
int len;
return (0);
do {
const char *q, *endp;
break;
/* Now remove the bad privilege endp points to */
if (q == NULL)
if (*badp != '\0')
/* Memset above guarantees NUL termination */
/* LINTED */
/* excise bad privilege; strtok ignores 2x sep */
}
"pam_setcred: can't parse privilege specification: %m\n");
return (-1);
} else if (*badp != '\0') {
"pam_setcred: unrecognized privilege(s): %s\n", badp);
}
return (0);
}
/*
* unix_cred - pam_sm_setcred
*
* Entry flags = PAM_ESTABLISH_CRED, set up Solaris Unix cred.
* PAM_DELETE_CRED, NOP, return PAM_SUCCESS.
* PAM_REINITIALIZE_CRED, set up Solaris Unix cred,
* or merge the current context with the new
* user.
* PAM_REFRESH_CRED, set up Solaris Unix cred.
* PAM_SILENT, print no messages to user.
*
* Returns PAM_SUCCESS, if all successful.
* PAM_CRED_ERR, if unable to set credentials.
* PAM_USER_UNKNOWN, if PAM_USER not set, or unable to find
* user in databases.
* user's audit state.
*/
int
{
int i;
int debug = 0;
int ret = PAM_SUCCESS;
char *user;
char *auser;
char *rhost;
char *tty;
userattr_t *ua;
char buf[PROJECT_BUFSZ];
int error;
char *projname;
char *kvs;
char pwbuf[NSS_BUFLEN_PASSWD];
void *defp;
for (i = 0; i < argc; i++) {
debug = 1;
nowarn |= 1;
}
if (debug)
"pam_unix_cred: pam_sm_setcred(flags = %x, argc= %d)",
"pam_unix_cred: USER NULL or empty!\n");
return (PAM_USER_UNKNOWN);
}
if (debug)
"pam_unix_cred: user = %s, auser = %s, rhost = %s, "
"tty = %s", user,
tty);
/* validate flags */
case 0:
/* set default flag */
break;
case PAM_ESTABLISH_CRED:
case PAM_REINITIALIZE_CRED:
case PAM_REFRESH_CRED:
break;
case PAM_DELETE_CRED:
return (PAM_SUCCESS);
default:
"pam_unix_cred: invalid flags %x", flags);
return (PAM_SYSTEM_ERR);
}
/*
* if auditing on and process audit state not set,
* setup audit context for process.
*/
"pam_unix_cred: cannot create start audit session %m");
return (PAM_SYSTEM_ERR);
}
if (debug) {
int auditstate;
sizeof (auditstate)) != 0) {
}
"pam_unix_cred: state = %d, auid = %d", auditstate,
auid);
}
"pam_unix_cred: cannot get passwd entry for user = %s",
user);
goto adt_done;
}
if ((auid == AU_NOAUDITID) &&
(flags & PAM_ESTABLISH_CRED)) {
char apwbuf[NSS_BUFLEN_PASSWD];
errno = 0;
if (errno != 0)
"pam_unix_cred: cannot load "
"ttyname: %m.");
else
"pam_unix_cred: cannot load "
"ttyname.");
goto adt_done;
}
} else {
if (errno != 0)
"pam_unix_cred: cannot load "
"hostname: %m.");
else
"pam_unix_cred: cannot load "
"hostname.");
goto adt_done;
}
}
/*
* set up the initial audit for user coming
* from another user
*/
"pam_unix_cred: cannot set auser audit "
"%m");
goto adt_done;
}
ADT_UPDATE) != 0) {
"pam_unix_cred: cannot merge user audit "
"%m");
goto adt_done;
}
if (debug) {
"pam_unix_cred: new audit set for %d:%d",
}
} else {
/*
* No authenticated user or authenticated user is
* not a local user, no remote attribution, set
* up the initial audit as for direct user login
*/
"pam_unix_cred: cannot set user audit %m");
goto adt_done;
}
}
if (adt_set_proc(ah) != 0) {
"pam_unix_cred: cannot set process audit %m");
ret = PAM_CRED_ERR;
goto adt_done;
}
if (debug) {
"pam_unix_cred: new audit set for %d",
}
} else if ((auid != AU_NOAUDITID) &&
(flags & PAM_REINITIALIZE_CRED)) {
"pam_unix_cred: cannot set user audit %m");
goto adt_done;
}
if (adt_set_proc(ah) != 0) {
"pam_unix_cred: cannot set process audit %m");
ret = PAM_CRED_ERR;
goto adt_done;
}
if (debug) {
"pam_unix_cred: audit merged for %d:%d",
}
} else if (debug) {
"pam_unix_cred: audit already set for %d", auid);
}
if (adt_end_session(ah) != 0) {
"pam_unix_cred: unable to end audit session");
}
if (ret != PAM_SUCCESS)
return (ret);
/* Initialize the user's project */
return (PAM_BUF_ERR);
break;
}
}
} else {
}
} else {
}
/* projname points into kvs, so this is the first opportunity to free */
"pam_unix_cred: no default project for user %s", user);
if (!nowarn) {
}
return (PAM_SYSTEM_ERR);
}
switch (error) {
case SETPROJ_ERR_TASK:
"pam_unix_cred: project \"%s\" resource "
"control limit has been reached",
"Resource control limit has been "
"reached"));
} else {
"pam_unix_cred: user %s could not join "
"Could not join default project"));
}
if (!nowarn)
break;
case SETPROJ_ERR_POOL:
"Could not bind to resource pool"));
switch (errno) {
case EACCES:
"pam_unix_cred: project \"%s\" could not "
"bind to resource pool: No resource pool "
"accepting default bindings exists",
sizeof (messages[1]),
"No resource pool accepting "
"default bindings exists"));
break;
case ESRCH:
"pam_unix_cred: project \"%s\" could not "
"bind to resource pool: The resource pool "
sizeof (messages[1]),
"The specified resource pool "
"is unknown"));
break;
default:
sizeof (messages[1]),
"Failure during pool binding"));
"pam_unix_cred: project \"%s\" could not "
}
if (!nowarn)
break;
default:
/*
* Resource control assignment failed. Unlike
* newtask(1m), we treat this as an error.
*/
if (error < 0) {
/*
* This isn't supposed to happen, but in
* case it does, this error message
* doesn't use error as an index, like
* the others might.
*/
"pam_unix_cred: unkwown error joining "
sizeof (messages[0]),
"unkwown error joining project \"%s\""
KV_DELIMITER)) != NULL) {
"pam_unix_cred: %s resource control "
"assignment failed for project \"%s\"",
sizeof (messages[0]),
"%s resource control assignment failed for "
"project \"%s\""),
} else {
"pam_unix_cred: resource control "
"assignment failed for project \"%s\""
sizeof (messages[0]),
"resource control assignment failed for "
"project \"%s\" attribute %d"),
}
if (!nowarn)
}
return (PAM_SYSTEM_ERR);
}
goto out;
}
errno = 0;
}
/*
* Silently limit the privileges to those actually available
* in the current zone.
*/
tset = priv_allocset();
goto out;
}
goto out;
}
/*
* We set privilege awareness here so that I gets copied to
* P & E when the final setuid(uid) happens.
*/
"pam_setcred: setppriv(defaultpriv) failed: %m");
ret = PAM_CRED_ERR;
}
/*
* Silently limit the privileges to the limit set available.
*/
goto out;
}
/*
* In order not to suprise certain applications, we
* need to retain privilege awareness and thus we must
* also set P and E.
*/
"pam_setcred: setppriv(limitpriv) failed: %m");
ret = PAM_CRED_ERR;
}
}
(void) setpflags(PRIV_AWARE, 0);
out:
return (ret);
}