1 diff -urN pam-pld-0.77.3.org/configure.in pam-pld-0.77.3/configure.in
2 --- pam-pld-0.77.3.org/configure.in 2003-12-27 01:14:06.000000000 +0100
3 +++ pam-pld-0.77.3/configure.in 2003-12-27 03:27:48.069612592 +0100
5 AC_MSG_WARN(pam_cap module will not be built!))
6 AC_CHECK_LIB(opie, opieverify, opielib_present=true,
7 AC_MSG_WARN(pam_opie modules will not be built!))
8 +AC_CHECK_LIB(selinux, getfilecon, selinux_present=true,
9 + AC_MSG_WARN(SELinux support will not be enabled. pam_selinux and pam_selinux_check module will not be built!))
10 AC_MSG_CHECKING(for hosts_access in -lwrap)
14 AM_CONDITIONAL(CAPLIB_PRESENT, test x$caplib_present = xtrue)
15 AM_CONDITIONAL(WRAPLIB_PRESENT, test x$wraplib_present = xtrue)
16 AM_CONDITIONAL(OPIELIB_PRESENT, test x$opielib_present = xtrue)
17 +AM_CONDITIONAL(SELINUX_PRESENT, test x$selinux_present = xtrue)
18 AC_DEFINE(HAVE_CRACKLIB)
20 AC_MSG_CHECKING([where cracklib_dict is located])
22 modules/pam_make/Makefile
23 modules/pam_pwgen/Makefile
24 modules/pam_skey/Makefile
25 + modules/pam_selinux/Makefile
26 modules/pam_cap/Makefile
27 modules/pam_netid/Makefile
28 modules/pam_opie/Makefile
29 diff -urN pam-pld-0.77.3.org/modules/Makefile.am pam-pld-0.77.3/modules/Makefile.am
30 --- pam-pld-0.77.3.org/modules/Makefile.am 2003-12-27 01:14:07.000000000 +0100
31 +++ pam-pld-0.77.3/modules/Makefile.am 2003-12-27 03:23:40.874192008 +0100
33 pam_tally pam_time pam_unix pam_userdb pam_warn pam_wheel \
34 pam_console pam_make pam_xauth pam_pwgen pam_skey pam_opie \
35 pam_cap pam_netid pam_tcpd pam_usertty pam_utmp pam_pwexport \
37 + pam_debug pam_selinux
39 EXTRA_DIST = README register_static register_static.mk download-all
41 diff -urN pam-pld-0.77.3.org/modules/pam_selinux/Makefile.am pam-pld-0.77.3/modules/pam_selinux/Makefile.am
42 --- pam-pld-0.77.3.org/modules/pam_selinux/Makefile.am 1970-01-01 01:00:00.000000000 +0100
43 +++ pam-pld-0.77.3/modules/pam_selinux/Makefile.am 2003-12-27 03:33:53.700028320 +0100
45 +## Process this file with automake to produce Makefile.in
52 +modules_LTLIBRARIES = pam_selinux.la pam_selinux_check.la
55 +pam_selinux_la_SOURCES = pam_selinux.c
56 +pam_selinux_check_la_SOURCES = pam_selinux_check.c
60 +EXTRA_pam_selinux_la_SOURCES = pam_selinux.c
61 +EXTRA_pam_selinux_check_la_SOURCES = pam_selinux_check.c
63 +man_MANS = pam_selinux.8 pam_selinux_check.8
69 +pam_selinux_la_LIBADD = -lselinux
70 +pam_selinux_check_la_LIBADD = -lselinux
72 +modulesdir = /lib/security
74 +pam_selinux_la_CFLAGS = -I$(top_srcdir)/include -DWITH_SELINUX=1 $(DYNAMIC)
75 +pam_selinux_check_la_CFLAGS = -I$(top_srcdir)/include -DWITH_SELINUX=1 $(DYNAMIC)
77 +pam_selinux_la_LDFLAGS = -avoid-version -module
78 +pam_selinux_check_la_LDFLAGS= -avoid-version -module
82 +CLEANFILES = *~ $(TITLE).so $(TITLE)_check.so
90 +noinst_LTLIBRARIES = libpam_selinux.la libpam_selinux_check.la
91 +libpam_selinux_la_SOURCES = pam_selinux.c
92 +libpam_selinux_check_la_SOURCES = pam_selinux_check.c
93 +libpam_selinux_la_DEPENDENCIES = register_static_stamp
94 +libpam_selinux_check_la_DEPENDENCIES = register_static_stamp
95 +libpam_selinux_la_CFLAGS = -I. -I../.. -I$(top_srcdir)/include $(STATIC)
96 +libpam_selinux_check_la_CFLAGS = -I. -I../.. -I$(top_srcdir)/include $(STATIC)
101 +register_static_stamp:
102 + ( cd .. ; ./register_static $(TITLE) $(TITLE)/lib$(TITLE).la )
103 + ( cd .. ; ./register_static $(TITLE)_check $(TITLE)/lib$(TITLE)_check.la )
104 + touch register_static_stamp
106 diff -urN pam-pld-0.77.3.org/modules/pam_selinux/pam_selinux.8 pam-pld-0.77.3/modules/pam_selinux/pam_selinux.8
107 --- pam-pld-0.77.3.org/modules/pam_selinux/pam_selinux.8 1970-01-01 01:00:00.000000000 +0100
108 +++ pam-pld-0.77.3/modules/pam_selinux/pam_selinux.8 2003-12-27 01:14:20.000000000 +0100
110 +.TH pam_selinux 8 2003/08/26 "Red Hat Linux" "System Administrator's Manual"
112 +pam_selinux \- set the default security context after login via PAM.
114 +.B session optional /lib/security/pam_selinux.so
118 +In a nutshell, pam_selinux sets up the default security context for the next execed
121 +When an application opens a session using pam_selinux, the shell that gets
122 +executed will be run in the default security context, or if the user chooses
123 +and the pam file allows the selected security context. Also the controlling
124 +tty will have it's security context modified to match the users.
128 +turns on debugging via \fBsyslog(3)\fR.
130 +tells pam_selinux.so to allow the user to select the security context they will
131 +login with, if the user has more than one role.
133 +Do not try to setup the ttys security context.
135 +attempt to inform the user when security context is set.
138 +\fB/etc/pam.d/some-login-program\fP:
140 +auth required /lib/security/pam_unix.so
142 +session required /lib/security/pam_permit.so
143 +session optional /lib/security/pam_selinux.so
147 +Setting the following line will cause the login to fail
148 +auth sufficient /lib/security/pam_selinux.so verbose
152 +pam_selinux_check(8)
155 +Let's hope not, but if you find any, please email the author.
158 +Dan Walsh <dwalsh@redhat.com>
159 diff -urN pam-pld-0.77.3.org/modules/pam_selinux/pam_selinux.c pam-pld-0.77.3/modules/pam_selinux/pam_selinux.c
160 --- pam-pld-0.77.3.org/modules/pam_selinux/pam_selinux.c 1970-01-01 01:00:00.000000000 +0100
161 +++ pam-pld-0.77.3/modules/pam_selinux/pam_selinux.c 2003-12-27 01:14:20.000000000 +0100
163 +/******************************************************************************
164 + * A module for Linux-PAM that will set the default security context after login
167 + * Copyright (c) 2003 Red Hat, Inc.
168 + * Written by Dan Walsh <dwalsh@redhat.com>
170 + * Redistribution and use in source and binary forms, with or without
171 + * modification, are permitted provided that the following conditions
173 + * 1. Redistributions of source code must retain the above copyright
174 + * notice, and the entire permission notice in its entirety,
175 + * including the disclaimer of warranties.
176 + * 2. Redistributions in binary form must reproduce the above copyright
177 + * notice, this list of conditions and the following disclaimer in the
178 + * documentation and/or other materials provided with the distribution.
179 + * 3. The name of the author may not be used to endorse or promote
180 + * products derived from this software without specific prior
181 + * written permission.
183 + * ALTERNATIVELY, this product may be distributed under the terms of
184 + * the GNU Public License, in which case the provisions of the GPL are
185 + * required INSTEAD OF the above restrictions. (This clause is
186 + * necessary due to a potential bad interaction between the GPL and
187 + * the restrictions contained in a BSD-style copyright.)
189 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
190 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
191 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
192 + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
193 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
194 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
195 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
196 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
197 + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
198 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
199 + * OF THE POSSIBILITY OF SUCH DAMAGE.
204 +#define PAM_SM_SESSION
206 +#include "../../_pam_aconf.h"
216 +#include "../../_pam_aconf.h"
217 +#include <security/pam_modules.h>
218 +#include <security/_pam_macros.h>
219 +#include <security/_pam_modutil.h>
221 +#include <libintl.h>
222 +#define _(x) gettext(x)
224 +#ifndef PAM_SELINUX_MAIN
225 +#define MODULE "pam_selinux"
227 +#include <selinux/selinux.h>
228 +#include <selinux/get_context_list.h>
229 +#include <selinux/flask.h>
230 +#include <selinux/selinux.h>
231 +#include <selinux/context.h>
233 +/* Validate a tty pathname as actually belonging to a tty, and return its base
234 + * name if it's valid. */
235 +static int send_text( struct pam_conv *conv, const char *text, int debug) {
236 + struct pam_message message;
237 + const struct pam_message *messages[] = {&message};
238 + struct pam_response *responses;
239 + memset(&message, 0, sizeof(message));
240 + message.msg_style = PAM_TEXT_INFO;
241 + message.msg = text;
243 + syslog(LOG_DEBUG, MODULE ": %s", message.msg);
244 + return conv->conv(1, messages, &responses, conv->appdata_ptr);
246 +static int query_response( struct pam_conv *conv, const char *text,struct pam_response **responses, int debug) {
247 + struct pam_message message;
248 + const struct pam_message *messages[] = {&message};
249 + memset(&message, 0, sizeof(message));
250 + message.msg_style = PAM_PROMPT_ECHO_ON;
251 + message.msg = text;
253 + syslog(LOG_DEBUG, MODULE ": %s", message.msg);
254 + return conv->conv(1, messages, responses, conv->appdata_ptr);
256 +static const security_context_t
257 +select_context( pam_handle_t *pamh, security_context_t* contextlist,int debug)
259 + struct pam_conv *conv;
260 + if (pam_get_item(pamh, PAM_CONV, (const void**) &conv) == PAM_SUCCESS) {
261 + if (conv->conv != NULL) {
262 + struct pam_response *responses;
263 + char *text=calloc(PATH_MAX,1);
264 + snprintf(text, PATH_MAX,
265 + _("Your default context is %s. \n"), contextlist[0]);
266 + send_text(conv,text,debug);
268 + query_response(conv,_("Do you want to choose a different one? [n]"),&responses,debug);
269 + if ((responses[0].resp[0] == 'y') || (responses[0].resp[0] == 'Y'))
273 + char *prompt=_("Enter number of choice: ");
274 + int len=strlen(prompt);
275 + for (i = 0; contextlist[i]; i++) {
276 + len+=strlen(contextlist[i]) + 10;
278 + text=calloc(len,1);
279 + for (i = 0; contextlist[i]; i++) {
281 + "%s[%d] %s\n", text,i+1, contextlist[i]);
283 + strcat(text,prompt);
284 + while ((choice < 1) || (choice > i)) {
285 + query_response(conv,text,&responses,debug);
286 + choice = strtol (responses[0].resp, NULL, 10);
289 + return (security_context_t) strdup(contextlist[choice-1]);
293 + syslog(LOG_DEBUG, _("%s: bogus conversation function"),MODULE);
297 + syslog(LOG_DEBUG, _("%s: no conversation function"),MODULE);
299 + return (security_context_t) strdup(contextlist[0]);
301 +static const security_context_t
302 +manual_context( pam_handle_t *pamh, char *user, int debug)
304 + struct pam_conv *conv;
305 + security_context_t newcon;
306 + if (pam_get_item(pamh, PAM_CONV, (const void**) &conv) == PAM_SUCCESS) {
307 + if (conv->conv != NULL) {
308 + struct pam_response *responses;
310 + query_response(conv,_("Would you like to enter a security context? [y] "),&responses,debug);
311 + if ((responses[0].resp[0] == 'y') || (responses[0].resp[0] == 'Y') || responses[0].resp[0]=='\0')
313 + context_t new_context = context_new ("user:role:type");
314 + /* Allow the user to enter each field of the context individually */
315 + if (context_user_set (new_context, user))
317 + context_free (new_context);
320 + query_response(conv,_("role: "),&responses,debug);
321 + if (context_role_set (new_context, responses[0].resp))
323 + context_free (new_context);
326 + query_response(conv,_("type: "),&responses,debug);
327 + if (context_type_set (new_context, responses[0].resp))
329 + context_free (new_context);
332 + /* Get the string value of the context and see if it is valid. */
333 + if (!security_check_context(context_str(new_context))) {
334 + newcon = strdup(context_str(new_context));
335 + context_free (new_context);
339 + send_text(conv,_("Not a valid security context"),debug);
347 + syslog(LOG_DEBUG, _("%s: bogus conversation function"),MODULE);
351 + syslog(LOG_DEBUG, _("%s: no conversation function"),MODULE);
356 +static void security_restorelabel_tty(const char *tty,security_context_t context) {
357 + char ttybuf[PATH_MAX];
363 + if(strncmp("/dev/", tty, 5))
365 + snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty);
371 + if(!strncmp(tty, "/dev/pts", 8))
374 + if (setfilecon(ptr, context))
376 + syslog(LOG_NOTICE, _("Warning! Could not relabel %s with %s, not relabeling.\n"), ttybuf,context);
381 +static security_context_t security_label_tty(char *tty, security_context_t usercon) {
382 + char ttybuf[PATH_MAX];
384 + security_context_t newdev_context=NULL; /* The new context of a device */
385 + security_context_t prev_context=NULL; /* The new context of a device */
387 + if(strncmp("/dev/", tty, 5))
389 + snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty);
395 + if (getfilecon(ptr, &prev_context) < 0)
397 + syslog(LOG_NOTICE, _("Warning! Could not get current context for %s, not relabeling."), ptr);
400 + if( security_compute_relabel(usercon,prev_context,SECCLASS_CHR_FILE,&newdev_context)!=0) {
401 + syslog(LOG_NOTICE, _("Warning! Could not get new context for %s, not relabeling."), ptr);
402 + syslog(LOG_NOTICE, "usercon=%s, prev_context=%s\n", usercon, prev_context);
403 + freecon(prev_context);
406 + status=setfilecon(ptr,newdev_context);
407 + freecon(newdev_context);
410 + syslog(LOG_NOTICE, _("Warning! Could not relabel %s with %s, not relabeling."), ptr,newdev_context);
411 + freecon(prev_context);
414 + return prev_context;
417 +static security_context_t user_context=NULL;
418 +static security_context_t prev_user_context=NULL;
419 +static security_context_t ttyn_context=NULL; /* The current context of ttyn device */
420 +static int selinux_enabled=0;
421 +static char *ttyn=NULL;
423 +/* Tell the user that access has been granted. */
425 +verbose_message(pam_handle_t *pamh, char *msg, int debug)
427 + struct pam_conv *conv;
428 + struct pam_message message;
429 + const struct pam_message *messages[] = {&message};
430 + struct pam_response *responses;
431 + if (pam_get_item(pamh, PAM_CONV, (const void**) &conv) == PAM_SUCCESS) {
432 + if (conv->conv != NULL) {
433 + char text[PATH_MAX];
434 + memset(&message, 0, sizeof(message));
435 + message.msg_style = PAM_TEXT_INFO;
436 + snprintf(text, sizeof(text), msg);
438 + message.msg = text;
440 + syslog(LOG_DEBUG, MODULE ": %s", message.msg);
441 + conv->conv(1, messages, &responses, conv->appdata_ptr);
444 + syslog(LOG_DEBUG, _("%s: bogus conversation function"),MODULE);
448 + syslog(LOG_DEBUG,_("%s: no conversation function"),MODULE);
453 +pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
455 + /* Fail by default. */
456 + return PAM_AUTH_ERR;
460 +pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
462 + return PAM_SUCCESS;
466 +pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
468 + int i, debug = 0, ttys=1,verbose=0,multiple=0;
470 + security_context_t* contextlist=NULL;
471 + int num_contexts = 0;
472 + char *username=NULL;
473 + const char *tty=NULL;
474 + /* Parse arguments. */
475 + if (!(selinux_enabled = is_selinux_enabled()) )
477 + return PAM_SUCCESS;
479 + for (i = 0; i < argc; i++) {
480 + if (strcmp(argv[i], "debug") == 0) {
483 + if (strcmp(argv[i], "nottys") == 0) {
486 + if (strcmp(argv[i], "verbose") == 0) {
489 + if (strcmp(argv[i], "multiple") == 0) {
494 + if (pam_get_item(pamh, PAM_USER, (const void**)&username) != PAM_SUCCESS) {
495 + return PAM_AUTH_ERR;
497 + num_contexts = get_ordered_context_list(username, 0, &contextlist);
498 + if (num_contexts > 0) {
500 + user_context = select_context(pamh,contextlist, debug);
501 + freeconary(contextlist);
503 + syslog (LOG_ERR, _("%s: query_user_context failed"), argv[0]);
504 + return PAM_AUTH_ERR;
507 + user_context = (security_context_t) strdup(contextlist[0]);
508 + freeconary(contextlist);
511 + user_context = manual_context(pamh,username,debug);
512 + if (user_context == NULL) {
513 + syslog (LOG_ERR, _("Unable to get valid context for %s"), username);
514 + return PAM_AUTH_ERR;
517 + if (getexeccon(&prev_user_context)<0) {
518 + prev_user_context=NULL;
521 + /* Get the name of the terminal. */
522 + if (pam_get_item(pamh, PAM_TTY, (const void**)&tty) != PAM_SUCCESS) {
525 + if ((tty == NULL) || (strlen(tty) == 0)) {
526 + tty = ttyname(STDIN_FILENO);
527 + if ((tty == NULL) || (strlen(tty) == 0)) {
528 + tty = ttyname(STDOUT_FILENO);
530 + if ((tty == NULL) || (strlen(tty) == 0)) {
531 + tty = ttyname(STDERR_FILENO);
535 + if(ttys && tty && strncmp(tty, "NODEV", 5) ) {
537 + ttyn_context=security_label_tty(ttyn,user_context);
539 + ret = setexeccon(user_context);
540 + if (ret==0 && verbose) {
541 + char msg[PATH_MAX];
542 + snprintf(msg, sizeof(msg),
543 + _("Security Context %s Assigned"), user_context);
544 + verbose_message(pamh, msg, debug);
547 + syslog(LOG_ERR, _("Error! Unable to set %s executable context %s."),username, user_context);
548 + freecon(user_context);
549 + return PAM_AUTH_ERR;
552 + syslog(LOG_DEBUG, _("%s: set %s security context to %s"),MODULE, username, user_context);
554 + freecon(user_context);
556 + return PAM_SUCCESS;
560 +pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
562 + int i, debug = 0,status=0;
563 + if (! (selinux_enabled ))
565 + return PAM_SUCCESS;
567 + /* Parse arguments. */
568 + for (i = 0; i < argc; i++) {
569 + if (strcmp(argv[i], "debug") == 0) {
575 + security_restorelabel_tty(ttyn,ttyn_context);
576 + freecon(ttyn_context);
580 + status=setexeccon(prev_user_context);
581 + freecon(prev_user_context);
583 + syslog(LOG_ERR, _("Error! Unable to set executable context %s."), prev_user_context);
584 + return PAM_AUTH_ERR;
588 + syslog(LOG_DEBUG, _("%s: setcontext back to orginal"),MODULE);
590 + return PAM_SUCCESS;
593 +#else /* PAM_SELINUX_MAIN */
595 +/************************************************************************
597 + * All PAM code goes in this section.
599 + ************************************************************************/
601 +#include <unistd.h> /* for getuid(), exit(), getopt() */
603 +#include <sys/wait.h> /* for wait() */
605 +#include <security/pam_appl.h> /* for PAM functions */
606 +#include <security/pam_misc.h> /* for misc_conv PAM utility function */
608 +#define SERVICE_NAME "pam_selinux_check" /* the name of this program for PAM */
609 + /* The file containing the context to run
610 + * the scripts under. */
611 +int authenticate_via_pam( const char *user , pam_handle_t **pamh);
613 +/* authenticate_via_pam()
617 + * return: value condition
619 + * 1 pam thinks that the user authenticated themselves properly
622 + * this function uses pam to authenticate the user running this
623 + * program. this is the only function in this program that makes pam
628 +int authenticate_via_pam( const char *user , pam_handle_t **pamh) {
630 + struct pam_conv *conv;
631 + int result = 0; /* our result, set to 0 (not authenticated) by default */
633 + /* this is a jump table of functions for pam to use when it wants to *
634 + * communicate with the user. we'll be using misc_conv(), which is *
635 + * provided for us via pam_misc.h. */
636 + struct pam_conv pam_conversation = {
640 + conv = &pam_conversation;
643 + /* make `p_pam_handle' a valid pam handle so we can use it when *
644 + * calling pam functions. */
645 + if( PAM_SUCCESS != pam_start( SERVICE_NAME,
649 + fprintf( stderr, _("failed to initialize PAM\n") );
653 + if( PAM_SUCCESS != pam_set_item(*pamh, PAM_RUSER, user))
655 + fprintf( stderr, _("failed to pam_set_item()\n") );
659 + /* Ask PAM to authenticate the user running this program */
660 + if( PAM_SUCCESS == pam_authenticate(*pamh,0) ) {
661 + result = 1; /* user authenticated OK! */
663 + pam_open_session(*pamh, 0);
666 +} /* authenticate_via_pam() */
668 +int main(int argc, char **argv) {
669 + pam_handle_t *pamh;
671 + if (!authenticate_via_pam(argv[1],&pamh))
675 + if (childPid < 0) {
677 + /* error in fork() */
678 + fprintf(stderr, _("login: failure forking: %s"), strerror(errsv));
679 + pam_close_session(pamh, 0);
680 + /* We're done with PAM. Free `pam_handle'. */
681 + pam_end( pamh, PAM_SUCCESS );
685 + close(0); close(1); close(2);
686 + struct sigaction sa;
687 + memset(&sa,0,sizeof(sa));
688 + sa.sa_handler = SIG_IGN;
689 + sigaction(SIGQUIT, &sa, NULL);
690 + sigaction(SIGINT, &sa, NULL);
691 + while(wait(NULL) == -1 && errno == EINTR) /**/ ;
692 + openlog("login", LOG_ODELAY, LOG_AUTHPRIV);
693 + pam_close_session(pamh, 0);
694 + /* We're done with PAM. Free `pam_handle'. */
695 + pam_end( pamh, PAM_SUCCESS );
700 + execv("/bin/sh",argv);
701 + fprintf(stderr,"Failure\n");
705 diff -urN pam-pld-0.77.3.org/modules/pam_selinux/pam_selinux_check.8 pam-pld-0.77.3/modules/pam_selinux/pam_selinux_check.8
706 --- pam-pld-0.77.3.org/modules/pam_selinux/pam_selinux_check.8 1970-01-01 01:00:00.000000000 +0100
707 +++ pam-pld-0.77.3/modules/pam_selinux/pam_selinux_check.8 2003-12-27 01:14:20.000000000 +0100
709 +.TH pam_selinux_check 8 2002/05/23 "Red Hat Linux" "System Administrator's Manual"
711 +pam_selinux_check \- login program to test pam_selinux_check
713 +.B pam_selinux_check [user]
718 +.B pam_selinux_check
719 +will prompt for user
723 +The user to login as.
726 +You must setup a /etc/pam.d/pam_selinux_check file, in order for the check to work.
728 +When checking if a selinux is valid,
729 +.B pam_selinux_check
730 +returns an exit code of 0 for success and > 0 on error:
733 +1: Authentication failure
740 +Let's hope not, but if you find any, please email the author.
743 +Dan Walsh <dwalsh@redhat.com>
744 diff -urN pam-pld-0.77.3.org/modules/pam_selinux/pam_selinux_check.c pam-pld-0.77.3/modules/pam_selinux/pam_selinux_check.c
745 --- pam-pld-0.77.3.org/modules/pam_selinux/pam_selinux_check.c 1970-01-01 01:00:00.000000000 +0100
746 +++ pam-pld-0.77.3/modules/pam_selinux/pam_selinux_check.c 2003-12-27 01:14:20.000000000 +0100
748 +/******************************************************************************
749 + * A module for Linux-PAM that will set the default security context after login
752 + * Copyright (c) 2003 Red Hat, Inc.
753 + * Written by Dan Walsh <dwalsh@redhat.com>
755 + * Redistribution and use in source and binary forms, with or without
756 + * modification, are permitted provided that the following conditions
758 + * 1. Redistributions of source code must retain the above copyright
759 + * notice, and the entire permission notice in its entirety,
760 + * including the disclaimer of warranties.
761 + * 2. Redistributions in binary form must reproduce the above copyright
762 + * notice, this list of conditions and the following disclaimer in the
763 + * documentation and/or other materials provided with the distribution.
764 + * 3. The name of the author may not be used to endorse or promote
765 + * products derived from this software without specific prior
766 + * written permission.
768 + * ALTERNATIVELY, this product may be distributed under the terms of
769 + * the GNU Public License, in which case the provisions of the GPL are
770 + * required INSTEAD OF the above restrictions. (This clause is
771 + * necessary due to a potential bad interaction between the GPL and
772 + * the restrictions contained in a BSD-style copyright.)
774 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
775 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
776 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
777 + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
778 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
779 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
780 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
781 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
782 + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
783 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
784 + * OF THE POSSIBILITY OF SUCH DAMAGE.
788 +#define PAM_SELINUX_MAIN 1
789 +#include "pam_selinux.c"
791 diff -urN pam-pld-0.77.3.org/modules/pam_selinux/README pam-pld-0.77.3/modules/pam_selinux/README
792 --- pam-pld-0.77.3.org/modules/pam_selinux/README 1970-01-01 01:00:00.000000000 +0100
793 +++ pam-pld-0.77.3/modules/pam_selinux/README 2003-12-27 01:14:20.000000000 +0100
795 +This is pam_selinux, a module for setting the default security context after
798 +Background: SELinux provides a mechanism for allowing people to login with
799 +different security contexts.
801 +The module takes these arguments:
802 +The module takes these arguments:
803 + debug Log debug messages (with priority DEBUG) to syslog.
804 + nottys Do not set security context on controlling tty
805 + verbose Attempt to tell the user when security context is set.
807 +Dan Walsh <dwalsh@redhat.com>
810 diff -urN pam-pld-0.77.3.org/modules/pam_unix/lckpwdf.-c pam-pld-0.77.3/modules/pam_unix/lckpwdf.-c
811 --- pam-pld-0.77.3.org/modules/pam_unix/lckpwdf.-c 2003-12-27 01:14:07.000000000 +0100
812 +++ pam-pld-0.77.3/modules/pam_unix/lckpwdf.-c 2003-12-27 01:14:20.000000000 +0100
818 +#include <selinux/selinux.h>
821 #define LOCKFILE "/etc/.pwd.lock"
828 + if(is_selinux_enabled())
830 + lockfd = open(LOCKFILE, O_WRONLY);
831 + if(lockfd == -1 && errno == ENOENT)
833 + security_context_t create_context;
836 + if(getfilecon("/etc/passwd", &create_context))
838 + rc = setfscreatecon(create_context);
839 + freecon(create_context);
842 + lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
843 + if(setfscreatecon(NULL))
849 lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
852 diff -urN pam-pld-0.77.3.org/modules/pam_unix/Makefile.am pam-pld-0.77.3/modules/pam_unix/Makefile.am
853 --- pam-pld-0.77.3.org/modules/pam_unix/Makefile.am 2003-12-27 01:14:07.000000000 +0100
854 +++ pam-pld-0.77.3/modules/pam_unix/Makefile.am 2003-12-27 03:33:35.157847160 +0100
856 modulesdir = /lib/security
860 +LIBSELINUX = -lselinux
861 +LIBSELINUX_DEFS = -DWITH_SELINUX=1
867 AM_CPPFLAGS = -DCHKPWD_HELPER=\"$(sbindir)/$(sbin_PROGRAMS)\" \
868 -I$(top_srcdir)/include \
869 -I$(top_srcdir)/pamcrypt/include
870 -pam_unix_la_CFLAGS = $(DYNAMIC)
871 +pam_unix_la_CFLAGS = $(LIBSELINUX_DEFS) $(DYNAMIC)
874 modules_LTLIBRARIES = pam_unix.la
879 -pam_unix_la_LIBADD = -lnsl -lcrack ../../pamcrypt/libpamcrypt.la
880 +pam_unix_la_LIBADD = -lnsl -lcrack $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
882 -pam_unix_la_LIBADD = -lnsl ../../pamcrypt/libpamcrypt.la
883 +pam_unix_la_LIBADD = -lnsl $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
887 -pam_unix_la_LIBADD = -lcrack ../../pamcrypt/libpamcrypt.la
888 +pam_unix_la_LIBADD = -lcrack $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
890 -pam_unix_la_LIBADD = ../../pamcrypt/libpamcrypt.la
891 +pam_unix_la_LIBADD = $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
896 sbin_PROGRAMS = unix_chkpwd
898 unix_chkpwd_SOURCES = unix_chkpwd.c
899 -unix_chkpwd_LDADD = ../../pamcrypt/libpamcrypt.la
900 +unix_chkpwd_CFLAGS = $(LIBSELINUX_DEFS)
901 +unix_chkpwd_LDADD = $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
903 EXTRA_DIST = README CHANGELOG
905 diff -urN pam-pld-0.77.3.org/modules/pam_unix/pam_unix_acct.c pam-pld-0.77.3/modules/pam_unix/pam_unix_acct.c
906 --- pam-pld-0.77.3.org/modules/pam_unix/pam_unix_acct.c 2003-12-27 01:14:07.000000000 +0100
907 +++ pam-pld-0.77.3/modules/pam_unix/pam_unix_acct.c 2003-12-27 01:14:20.000000000 +0100
911 #include <time.h> /* for time() */
912 +#include <linux/limits.h>
914 +#include <sys/wait.h>
916 +#include <selinux/selinux.h>
917 +#define SELINUX_ENABLED is_selinux_enabled()
919 +#define SELINUX_ENABLED 0
923 #include "security/_pam_macros.h"
925 #endif /* LINUX_PAM */
930 +struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user)
932 + int retval=0, child, fds[2];
933 + void (*sighandler)(int) = NULL;
934 + D(("running verify_binary"));
936 + /* create a pipe for the messages */
937 + if (pipe(fds) != 0) {
938 + D(("could not make pipe"));
939 + _log_err(LOG_ERR, pamh, "Could not make pipe %s",strerror(errno));
944 + if (off(UNIX_NOREAP, ctrl)) {
946 + * This code arranges that the demise of the child does not cause
947 + * the application to receive a signal it is not expecting - which
948 + * may kill the application or worse.
950 + * The "noreap" module argument is provided so that the admin can
951 + * override this behavior.
953 + sighandler = signal(SIGCHLD, SIG_DFL);
960 + struct rlimit rlim;
961 + static char *envp[] = { NULL };
962 + char *args[] = { NULL, NULL, NULL, NULL };
964 + close(0); close(1);
965 + /* reopen stdin as pipe */
967 + dup2(fds[1], STDOUT_FILENO);
969 + /* XXX - should really tidy up PAM here too */
971 + if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
972 + for (i=2; i < rlim.rlim_max; i++) {
978 + /* exec binary helper */
979 + args[0] = x_strdup(CHKPWD_HELPER);
980 + args[1] = x_strdup(user);
981 + args[2] = x_strdup("verify");
983 + execve(CHKPWD_HELPER, args, envp);
985 + _log_err(LOG_ERR, pamh, "execve failed: %s",strerror(errno));
986 + /* should not get here: exit with error */
987 + D(("helper binary is not available"));
988 + exit(PAM_AUTHINFO_UNAVAIL);
993 + rc = read(fds[0], buf, sizeof(buf) - 1);
997 + sscanf(buf,"%ld:%ld:%ld:%ld:%ld:%ld",
998 + &spwd.sp_lstchg, /* last password change */
999 + &spwd.sp_min, /* days until change allowed. */
1000 + &spwd.sp_max, /* days before change required */
1001 + &spwd.sp_warn, /* days warning for expiration */
1002 + &spwd.sp_inact, /* days before account inactive */
1003 + &spwd.sp_expire); /* date when account expires */
1006 + _log_err(LOG_ERR, pamh, " ERROR %d:%s \n",rc, strerror(errno));
1010 + rc=waitpid(child, &retval, 0); /* wait for helper to complete */
1012 + _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
1013 + retval = PAM_AUTH_ERR;
1015 + retval = WEXITSTATUS(retval);
1018 + D(("fork failed"));
1019 + close(fds[0]);close(fds[1]);
1020 + retval = PAM_AUTH_ERR;
1023 + if (sighandler != NULL) {
1024 + (void) signal(SIGCHLD, sighandler); /* restore old signal handler */
1026 + D(("Returning %d",retval));
1027 + if (retval != PAM_SUCCESS) {
1033 * PAM framework looks for this entry-point to pass control to the
1034 * account management module.
1039 + if (!spent && SELINUX_ENABLED )
1040 + spent = _unix_run_verify_binary(pamh, ctrl, uname);
1043 return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */
1045 diff -urN pam-pld-0.77.3.org/modules/pam_unix/pam_unix_passwd.c pam-pld-0.77.3/modules/pam_unix/pam_unix_passwd.c
1046 --- pam-pld-0.77.3.org/modules/pam_unix/pam_unix_passwd.c 2003-12-27 01:14:07.000000000 +0100
1047 +++ pam-pld-0.77.3/modules/pam_unix/pam_unix_passwd.c 2003-12-27 03:09:39.984026744 +0100
1049 #include <rpc/rpc.h>
1050 #include <rpcsvc/yp_prot.h>
1051 #include <rpcsvc/ypclnt.h>
1053 +#include <signal.h>
1054 +#include <linux/limits.h>
1055 +#include <sys/wait.h>
1056 +static int selinux_enabled=-1;
1057 +#ifdef WITH_SELINUX
1058 +#include <selinux/selinux.h>
1059 +static security_context_t prev_context=NULL;
1060 +#define SELINUX_ENABLED (selinux_enabled != -1 ? selinux_enabled : selinux_enabled=is_selinux_enabled())
1062 +#define SELINUX_ENABLED 0
1068 @@ -260,6 +271,97 @@
1072 +static int _unix_run_shadow_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user, const char *fromwhat, const char *towhat)
1074 + int retval, child, fds[2];
1075 + void (*sighandler)(int) = NULL;
1078 + /* create a pipe for the password */
1079 + if (pipe(fds) != 0) {
1080 + D(("could not make pipe"));
1081 + return PAM_AUTH_ERR;
1084 + if (off(UNIX_NOREAP, ctrl)) {
1086 + * This code arranges that the demise of the child does not cause
1087 + * the application to receive a signal it is not expecting - which
1088 + * may kill the application or worse.
1090 + * The "noreap" module argument is provided so that the admin can
1091 + * override this behavior.
1093 + sighandler = signal(SIGCHLD, SIG_DFL);
1100 + struct rlimit rlim;
1101 + static char *envp[] = { NULL };
1102 + char *args[] = { NULL, NULL, NULL, NULL };
1104 + /* XXX - should really tidy up PAM here too */
1106 + close(0); close(1);
1107 + /* reopen stdin as pipe */
1109 + dup2(fds[0], STDIN_FILENO);
1111 + if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
1112 + for (i=2; i < rlim.rlim_max; i++) {
1117 + /* exec binary helper */
1118 + args[0] = x_strdup(CHKPWD_HELPER);
1119 + args[1] = x_strdup(user);
1120 + args[2] = x_strdup("shadow");
1122 + execve(CHKPWD_HELPER, args, envp);
1124 + /* should not get here: exit with error */
1125 + D(("helper binary is not available"));
1126 + exit(PAM_AUTHINFO_UNAVAIL);
1127 + } else if (child > 0) {
1128 + /* wait for child */
1129 + /* if the stored password is NULL */
1132 + write(fds[1], fromwhat, strlen(fromwhat)+1);
1134 + write(fds[1], "", 1);
1136 + write(fds[1], towhat, strlen(towhat)+1);
1139 + write(fds[1], "", 1);
1141 + close(fds[0]); /* close here to avoid possible SIGPIPE above */
1143 + rc=waitpid(child, &retval, 0); /* wait for helper to complete */
1145 + _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
1146 + retval = PAM_AUTH_ERR;
1148 + retval = WEXITSTATUS(retval);
1151 + D(("fork failed"));
1154 + retval = PAM_AUTH_ERR;
1157 + if (sighandler != NULL) {
1158 + (void) signal(SIGCHLD, sighandler); /* restore old signal handler */
1163 static int check_old_password(const char *forwho, const char *newpass)
1165 static char buf[16384];
1166 @@ -318,16 +420,41 @@
1169 oldmask = umask(077);
1171 + if (SELINUX_ENABLED) {
1172 + security_context_t passwd_context = NULL;
1174 + if (getfilecon("/etc/passwd",&passwd_context) < 0) {
1175 + return PAM_AUTHTOK_ERR;
1178 + if (getfscreatecon(&prev_context)<0) {
1179 + freecon(passwd_context);
1180 + return PAM_AUTHTOK_ERR;
1183 + if (setfscreatecon(passwd_context)) {
1184 + freecon(passwd_context);
1185 + freecon(prev_context);
1186 + return PAM_AUTHTOK_ERR;
1189 + freecon(passwd_context);
1192 pwfile = fopen(OPW_TMPFILE, "w");
1194 - if (pwfile == NULL) {
1195 - return PAM_AUTHTOK_ERR;
1198 + if (pwfile == NULL) {
1203 opwfile = fopen(OLD_PASSWORDS_FILE, "r");
1204 if (opwfile == NULL) {
1206 - return PAM_AUTHTOK_ERR;
1212 chown(OPW_TMPFILE, 0, 0);
1213 @@ -388,8 +515,20 @@
1220 rename(OPW_TMPFILE, OLD_PASSWORDS_FILE);
1221 +#ifdef WITH_SELINUX
1222 + if (SELINUX_ENABLED) {
1223 + if (setfscreatecon(prev_context)) {
1227 + freecon(prev_context);
1228 + prev_context=NULL;
1234 unlink(OPW_TMPFILE);
1235 @@ -406,16 +545,36 @@
1238 oldmask = umask(077);
1239 +#ifdef WITH_SELINUX
1240 + if (SELINUX_ENABLED) {
1241 + security_context_t passwd_context=NULL;
1242 + if (getfilecon("/etc/passwd",&passwd_context)<0) {
1243 + return PAM_AUTHTOK_ERR;
1245 + if (getfscreatecon(&prev_context)<0) {
1246 + freecon(passwd_context);
1247 + return PAM_AUTHTOK_ERR;
1249 + if (setfscreatecon(passwd_context)) {
1250 + freecon(passwd_context);
1251 + freecon(prev_context);
1252 + return PAM_AUTHTOK_ERR;
1254 + freecon(passwd_context);
1257 pwfile = fopen(PW_TMPFILE, "w");
1259 - if (pwfile == NULL) {
1260 - return PAM_AUTHTOK_ERR;
1262 + if (pwfile == NULL) {
1267 opwfile = fopen("/etc/passwd", "r");
1268 if (opwfile == NULL) {
1270 - return PAM_AUTHTOK_ERR;
1276 chown(PW_TMPFILE, 0, 0);
1277 @@ -447,9 +606,22 @@
1283 rename(PW_TMPFILE, "/etc/passwd");
1284 _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
1286 +#ifdef WITH_SELINUX
1287 + if (SELINUX_ENABLED) {
1288 + if (setfscreatecon(prev_context)) {
1292 + freecon(prev_context);
1293 + prev_context=NULL;
1300 @@ -465,20 +637,43 @@
1303 spwdent = getspnam(forwho);
1304 - if (spwdent == NULL) {
1305 - return PAM_USER_UNKNOWN;
1308 + if (spwdent == NULL) {
1309 + return PAM_USER_UNKNOWN;
1312 oldmask = umask(077);
1313 +#ifdef WITH_SELINUX
1314 + if (SELINUX_ENABLED) {
1315 + security_context_t shadow_context=NULL;
1316 + if (getfilecon("/etc/shadow",&shadow_context)<0) {
1317 + return PAM_AUTHTOK_ERR;
1319 + if (getfscreatecon(&prev_context)<0) {
1320 + freecon(shadow_context);
1321 + return PAM_AUTHTOK_ERR;
1323 + if (setfscreatecon(shadow_context)) {
1324 + freecon(shadow_context);
1325 + freecon(prev_context);
1326 + return PAM_AUTHTOK_ERR;
1328 + freecon(shadow_context);
1331 pwfile = fopen(SH_TMPFILE, "w");
1333 - if (pwfile == NULL) {
1334 - return PAM_AUTHTOK_ERR;
1337 + if (pwfile == NULL) {
1342 opwfile = fopen("/etc/shadow", "r");
1343 if (opwfile == NULL) {
1345 - return PAM_AUTHTOK_ERR;
1350 chown(SH_TMPFILE, 0, 0);
1351 @@ -508,8 +703,22 @@
1357 rename(SH_TMPFILE, "/etc/shadow");
1359 +#ifdef WITH_SELINUX
1360 + if (SELINUX_ENABLED) {
1361 + if (setfscreatecon(prev_context)) {
1365 + freecon(prev_context);
1366 + prev_context=NULL;
1376 if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) {
1377 retval = _update_shadow(forwho, towhat);
1378 + if (retval != PAM_SUCCESS && SELINUX_ENABLED)
1379 + retval = _unix_run_shadow_binary(pamh, ctrl, forwho, fromwhat, towhat);
1380 if (retval == PAM_SUCCESS)
1381 retval = _update_passwd(pamh, forwho, "x");
1387 -static int _unix_verify_shadow(const char *user, unsigned int ctrl)
1388 +static int _unix_verify_shadow(pam_handle_t *pamh, const char *user, unsigned int ctrl)
1390 struct passwd *pwd = NULL; /* Password and shadow password */
1391 struct spwd *spwdent = NULL; /* file entries for the user */
1393 spwdent = getspnam(user);
1396 + if (spwdent == NULL && SELINUX_ENABLED )
1397 + spwdent = _unix_run_verify_binary(pamh, ctrl, user);
1398 if (spwdent == NULL)
1399 return PAM_AUTHINFO_UNAVAIL;
1401 @@ -877,7 +1090,7 @@
1402 _log_err(LOG_CRIT, pamh,
1403 "failed to set PAM_OLDAUTHTOK");
1405 - retval = _unix_verify_shadow(user, ctrl);
1406 + retval = _unix_verify_shadow(pamh,user, ctrl);
1407 if (retval == PAM_AUTHTOK_ERR) {
1408 if (off(UNIX__IAMROOT, ctrl))
1409 _make_remark(pamh, ctrl, PAM_ERROR_MSG,
1410 @@ -926,7 +1139,7 @@
1414 - retval = _unix_verify_shadow(user, ctrl);
1415 + retval = _unix_verify_shadow(pamh, user, ctrl);
1416 if (retval != PAM_SUCCESS) {
1417 _log_err(LOG_NOTICE, pamh, "user not authenticated 2");
1419 diff -urN pam-pld-0.77.3.org/modules/pam_unix/support.c pam-pld-0.77.3/modules/pam_unix/support.c
1420 --- pam-pld-0.77.3.org/modules/pam_unix/support.c 2003-12-27 01:14:07.000000000 +0100
1421 +++ pam-pld-0.77.3/modules/pam_unix/support.c 2003-12-27 03:10:49.073523544 +0100
1426 +#include <linux/limits.h>
1432 +#ifdef WITH_SELINUX
1433 +#include <selinux/selinux.h>
1434 +#define SELINUX_ENABLED is_selinux_enabled()
1436 +#define SELINUX_ENABLED 0
1439 #include "security/_pam_macros.h"
1440 #include "security/pam_modules.h"
1442 @@ -464,18 +471,32 @@
1447 + struct rlimit rlim;
1448 static char *envp[] = { NULL };
1449 - char *args[] = { NULL, NULL, NULL };
1450 + char *args[] = { NULL, NULL, NULL, NULL };
1452 /* XXX - should really tidy up PAM here too */
1454 + close(0); close(1);
1455 /* reopen stdin as pipe */
1457 dup2(fds[0], STDIN_FILENO);
1459 + if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
1460 + for (i=2; i < rlim.rlim_max; i++) {
1465 /* exec binary helper */
1466 args[0] = x_strdup(CHKPWD_HELPER);
1467 args[1] = x_strdup(user);
1468 + if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */
1469 + args[2]=x_strdup("nullok");
1471 + args[2]=x_strdup("nonull");
1474 execve(CHKPWD_HELPER, args, envp);
1476 @@ -485,11 +506,7 @@
1477 } else if (child > 0) {
1478 /* wait for child */
1479 /* if the stored password is NULL */
1480 - if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */
1481 - write(fds[1], "nullok\0\0", 8);
1483 - write(fds[1], "nonull\0\0", 8);
1486 if (passwd != NULL) { /* send the password to the child */
1487 write(fds[1], passwd, strlen(passwd)+1);
1489 @@ -498,10 +515,17 @@
1491 close(fds[0]); /* close here to avoid possible SIGPIPE above */
1493 - (void) waitpid(child, &retval, 0); /* wait for helper to complete */
1494 - retval = (retval == 0) ? PAM_SUCCESS:PAM_AUTH_ERR;
1495 + rc=waitpid(child, &retval, 0); /* wait for helper to complete */
1497 + _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
1498 + retval = PAM_AUTH_ERR;
1500 + retval = WEXITSTATUS(retval);
1506 retval = PAM_AUTH_ERR;
1516 #ifdef HAVE_PAM_FAIL_DELAY
1519 retval = PAM_SUCCESS;
1520 if (pwd == NULL || salt == NULL || !strcmp(salt, "x")) {
1522 + if (geteuid() || SELINUX_ENABLED) {
1523 /* we are not root perhaps this is the reason? Run helper */
1524 D(("running helper binary"));
1525 retval = _unix_run_helper_binary(pamh, p, ctrl, name);
1526 diff -urN pam-pld-0.77.3.org/modules/pam_unix/support.h pam-pld-0.77.3/modules/pam_unix/support.h
1527 --- pam-pld-0.77.3.org/modules/pam_unix/support.h 2003-12-27 01:14:07.000000000 +0100
1528 +++ pam-pld-0.77.3/modules/pam_unix/support.h 2003-12-27 01:14:20.000000000 +0100
1530 ,const char *data_name
1531 ,const char **pass);
1533 +extern struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user);
1534 #endif /* _PAM_UNIX_SUPPORT_H */
1536 diff -urN pam-pld-0.77.3.org/modules/pam_unix/unix_chkpwd.c pam-pld-0.77.3/modules/pam_unix/unix_chkpwd.c
1537 --- pam-pld-0.77.3.org/modules/pam_unix/unix_chkpwd.c 2003-12-27 01:14:07.000000000 +0100
1538 +++ pam-pld-0.77.3/modules/pam_unix/unix_chkpwd.c 2003-12-27 02:58:53.004382600 +0100
1542 #include <sys/types.h>
1543 +#include <sys/stat.h>
1550 +static int selinux_enabled=-1;
1551 +#ifdef WITH_SELINUX
1552 +#include <selinux/selinux.h>
1553 +#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : selinux_enabled=is_selinux_enabled())
1554 +static security_context_t prev_context=NULL;
1556 +#define SELINUX_ENABLED 0
1559 #define MAXPASS 200 /* the maximum length of a password */
1561 +#include <security/_pam_types.h>
1562 #include "security/_pam_macros.h"
1564 #include "pam_crypt.h"
1566 (void) sigaction(SIGQUIT, &action, NULL);
1569 +static int _verify_account(const char * const uname)
1571 + struct spwd *spent;
1572 + struct passwd *pwent;
1574 + pwent = getpwnam(uname);
1576 + _log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname);
1577 + return PAM_USER_UNKNOWN;
1580 + spent = getspnam( uname );
1582 + _log_err(LOG_ALERT, "could not get username from shadow (%s))", uname);
1583 + return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */
1585 + printf("%ld:%ld:%ld:%ld:%ld:%ld",
1586 + spent->sp_lstchg, /* last password change */
1587 + spent->sp_min, /* days until change allowed. */
1588 + spent->sp_max, /* days before change required */
1589 + spent->sp_warn, /* days warning for expiration */
1590 + spent->sp_inact, /* days before account inactive */
1591 + spent->sp_expire); /* date when account expires */
1593 + return PAM_SUCCESS;
1596 static int _unix_verify_password(const char *name, const char *p, int opt)
1598 struct passwd *pwd = NULL;
1599 @@ -223,11 +261,171 @@
1603 + #define SH_TMPFILE "/etc/nshadow"
1604 + static int _update_shadow(const char *forwho)
1606 + struct spwd *spwdent = NULL, *stmpent = NULL;
1607 + FILE *pwfile, *opwfile;
1611 + char pass[MAXPASS + 1];
1612 + char towhat[MAXPASS + 1];
1615 + /* read the password from stdin (a pipe from the pam_unix module) */
1617 + npass = read(STDIN_FILENO, pass, MAXPASS);
1619 + if (npass < 0) { /* is it a valid password? */
1621 + _log_err(LOG_DEBUG, "no password supplied");
1622 + return PAM_AUTHTOK_ERR;
1624 + } else if (npass >= MAXPASS) {
1626 + _log_err(LOG_DEBUG, "password too long");
1627 + return PAM_AUTHTOK_ERR;
1630 + /* does pass agree with the official one? */
1632 + pass[npass] = '\0'; /* NUL terminate */
1633 + retval = _unix_verify_password(forwho, pass, 0);
1634 + if (retval != PAM_SUCCESS) {
1639 + /* read the password from stdin (a pipe from the pam_unix module) */
1641 + npass = read(STDIN_FILENO, towhat, MAXPASS);
1643 + if (npass < 0) { /* is it a valid password? */
1645 + _log_err(LOG_DEBUG, "no new password supplied");
1646 + return PAM_AUTHTOK_ERR;
1648 + } else if (npass >= MAXPASS) {
1650 + _log_err(LOG_DEBUG, "new password too long");
1651 + return PAM_AUTHTOK_ERR;
1655 + towhat[npass] = '\0'; /* NUL terminate */
1656 + spwdent = getspnam(forwho);
1657 + if (spwdent == NULL) {
1658 + return PAM_USER_UNKNOWN;
1660 + oldmask = umask(077);
1662 + #ifdef WITH_SELINUX
1663 + if (SELINUX_ENABLED) {
1664 + security_context_t shadow_context=NULL;
1665 + if (getfilecon("/etc/shadow",&shadow_context)<0) {
1666 + return PAM_AUTHTOK_ERR;
1668 + if (getfscreatecon(&prev_context)<0) {
1669 + freecon(shadow_context);
1670 + return PAM_AUTHTOK_ERR;
1672 + if (setfscreatecon(shadow_context)) {
1673 + freecon(shadow_context);
1674 + freecon(prev_context);
1675 + return PAM_AUTHTOK_ERR;
1677 + freecon(shadow_context);
1680 + pwfile = fopen(SH_TMPFILE, "w");
1682 + if (pwfile == NULL) {
1687 + opwfile = fopen("/etc/shadow", "r");
1688 + if (opwfile == NULL) {
1694 + if (fstat(fileno(opwfile), &st) == -1) {
1701 + if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
1707 + if (fchmod(fileno(pwfile), st.st_mode) == -1) {
1713 + stmpent = fgetspent(opwfile);
1716 + if (!strcmp(stmpent->sp_namp, forwho)) {
1717 + stmpent->sp_pwdp = towhat;
1718 + stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
1720 + D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
1723 + if (putspent(stmpent, pwfile)) {
1724 + D(("error writing entry to shadow file: %s\n", strerror(errno)));
1729 + stmpent = fgetspent(opwfile);
1733 + if (fclose(pwfile)) {
1734 + D(("error writing entries to shadow file: %s\n", strerror(errno)));
1740 + rename(SH_TMPFILE, "/etc/shadow");
1743 + #ifdef WITH_SELINUX
1744 + if (SELINUX_ENABLED) {
1745 + if (setfscreatecon(prev_context)) {
1749 + freecon(prev_context);
1750 + prev_context=NULL;
1755 + return PAM_SUCCESS;
1757 + unlink(SH_TMPFILE);
1758 + return PAM_AUTHTOK_ERR;
1763 int main(int argc, char *argv[])
1765 char pass[MAXPASS + 1];
1769 int force_failure = 0;
1770 int retval = UNIX_FAILED;
1776 - if (isatty(STDIN_FILENO)) {
1778 + if (isatty(STDIN_FILENO) || argc != 3 ) {
1780 ,"inappropriate use of Unix helper binary [UID=%d]"
1782 @@ -258,19 +455,43 @@
1787 - * determine the current user's name is
1789 - user = getuidname(getuid());
1791 - /* if the caller specifies the username, verify that user
1793 - if (strcmp(user, argv[1])) {
1794 - force_failure = 1;
1798 + * determine the current user's name is.
1799 + * On a SELinux enabled system, policy will prevent third parties from using
1800 + * unix_chkpwd as a password guesser. Leaving the existing check prevents
1801 + * su from working, Since the current uid is the users and the password is
1804 + if (SELINUX_ENABLED) {
1808 + user = getuidname(getuid());
1809 + /* if the caller specifies the username, verify that user
1811 + if (strcmp(user, argv[1])) {
1812 + return UNIX_FAILED;
1818 + if (strncmp(argv[2], "verify", 8) == 0) {
1819 + /* Get the account information from the shadow file */
1820 + return _verify_account(argv[1]);
1823 + if (strncmp(option, "shadow", 8) == 0) {
1824 + /* Attempting to change the password */
1825 + return _update_shadow(argv[1]);
1827 + /* read the nullok/nonull option */
1828 + if (strncmp(option, "nullok", 8) == 0)
1833 - /* read the nullok/nonull option */
1834 + /* read the password from stdin (a pipe from the pam_unix module) */
1836 npass = read(STDIN_FILENO, option, 8);