]> git.pld-linux.org Git - packages/pam.git/blob - pam-selinux-1.patch
- updated
[packages/pam.git] / pam-selinux-1.patch
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
4 @@ -282,6 +282,8 @@
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)
11  oldLIBS=$LIBS
12  LIBS="$LIBS -lwrap"
13 @@ -301,6 +303,7 @@
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)
19  
20  AC_MSG_CHECKING([where cracklib_dict is located])
21 @@ -443,6 +446,7 @@
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
32 @@ -10,7 +10,7 @@
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 \
36 -         pam_debug
37 +         pam_debug pam_selinux
38  
39  EXTRA_DIST             = README register_static register_static.mk download-all
40  
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
44 @@ -0,0 +1,61 @@
45 +## Process this file with automake to produce Makefile.in
46 +
47 +@SET_MAKE@
48 +
49 +if SELINUX_PRESENT
50 +
51 +if DYNAMIC_MODULES
52 +modules_LTLIBRARIES    = pam_selinux.la pam_selinux_check.la
53 +endif
54 +
55 +pam_selinux_la_SOURCES = pam_selinux.c
56 +pam_selinux_check_la_SOURCES = pam_selinux_check.c
57 +
58 +else
59 +
60 +EXTRA_pam_selinux_la_SOURCES = pam_selinux.c
61 +EXTRA_pam_selinux_check_la_SOURCES = pam_selinux_check.c
62 +
63 +man_MANS               = pam_selinux.8 pam_selinux_check.8
64 +
65 +endif
66 +
67 +TITLE                  = pam_selinux
68 +
69 +pam_selinux_la_LIBADD  = -lselinux
70 +pam_selinux_check_la_LIBADD    = -lselinux
71 +
72 +modulesdir             = /lib/security
73 +
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)
76 +
77 +pam_selinux_la_LDFLAGS = -avoid-version -module
78 +pam_selinux_check_la_LDFLAGS= -avoid-version -module
79 +
80 +EXTRA_DIST             = README
81 +
82 +CLEANFILES             = *~ $(TITLE).so $(TITLE)_check.so
83 +
84 +clean-local:
85 +       rm -rf static
86 +
87 +if STATIC_MODULES
88 +
89 +if SELINX_PRESENT
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)
97 +endif
98 +
99 +endif
100 +
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
105 +
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
109 @@ -0,0 +1,49 @@
110 +.TH pam_selinux 8 2003/08/26 "Red Hat Linux" "System Administrator's Manual"
111 +.SH NAME
112 +pam_selinux \- set the default security context after login via PAM.
113 +.SH SYNOPSIS
114 +.B session optional /lib/security/pam_selinux.so
115 +.br
116 +
117 +.SH DESCRIPTION
118 +In a nutshell, pam_selinux sets up the default security context for the next execed 
119 +shell.  
120 +
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.
125 +
126 +.SH ARGUMENTS
127 +.IP debug
128 +turns on debugging via \fBsyslog(3)\fR.
129 +.IP multiple
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.
132 +.IP nottys
133 +Do not try to setup the ttys security context.
134 +.IP verbose
135 +attempt to inform the user when security context is set.
136 +
137 +.SH EXAMPLE
138 +\fB/etc/pam.d/some-login-program\fP:
139 +.br
140 +auth required   /lib/security/pam_unix.so
141 +.br
142 +session required /lib/security/pam_permit.so
143 +session optional /lib/security/pam_selinux.so
144 +.br
145 +
146 +.SH CAVEATS
147 +Setting the following line will cause the login to fail
148 +auth sufficient /lib/security/pam_selinux.so verbose
149 +
150 +
151 +.SH SEE ALSO
152 +pam_selinux_check(8)
153 +
154 +.SH BUGS
155 +Let's hope not, but if you find any, please email the author.  
156 +
157 +.SH 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
162 @@ -0,0 +1,542 @@
163 +/******************************************************************************
164 + * A module for Linux-PAM that will set the default security context after login 
165 + * via PAM.
166 + *
167 + * Copyright (c) 2003 Red Hat, Inc.
168 + * Written by Dan Walsh <dwalsh@redhat.com>
169 + *
170 + * Redistribution and use in source and binary forms, with or without
171 + * modification, are permitted provided that the following conditions
172 + * are met:
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.
182 + *
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.)
188 + *
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.
200 + *
201 + */
202 +
203 +#define PAM_SM_AUTH
204 +#define PAM_SM_SESSION
205 +
206 +#include "../../_pam_aconf.h"
207 +
208 +#include <errno.h>
209 +#include <limits.h>
210 +#include <pwd.h>
211 +#include <stdio.h>
212 +#include <stdlib.h>
213 +#include <string.h>
214 +#include <unistd.h>
215 +
216 +#include "../../_pam_aconf.h"
217 +#include <security/pam_modules.h>
218 +#include <security/_pam_macros.h>
219 +#include <security/_pam_modutil.h>
220 +
221 +#include <libintl.h>
222 +#define _(x) gettext(x)
223 +
224 +#ifndef PAM_SELINUX_MAIN
225 +#define MODULE "pam_selinux"
226 +
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>
232 +
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;
242 +  if (debug)
243 +    syslog(LOG_DEBUG, MODULE ": %s", message.msg);
244 +  return conv->conv(1, messages, &responses, conv->appdata_ptr);
245 +}
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;
252 +  if (debug)
253 +    syslog(LOG_DEBUG, MODULE ": %s", message.msg);
254 +  return conv->conv(1, messages, responses, conv->appdata_ptr);
255 +}
256 +static const security_context_t 
257 +select_context( pam_handle_t *pamh, security_context_t* contextlist,int debug)
258 +{
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);
267 +      free(text);
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'))
270 +       {
271 +         int choice=0;
272 +         int i;
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; 
277 +         }
278 +         text=calloc(len,1);
279 +         for (i = 0; contextlist[i]; i++) {
280 +           sprintf(text,
281 +                    "%s[%d] %s\n", text,i+1, contextlist[i]);
282 +         }
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);
287 +         }
288 +         free(text);
289 +         return (security_context_t) strdup(contextlist[choice-1]);  
290 +       }
291 +    } else {
292 +      if (debug)
293 +       syslog(LOG_DEBUG, _("%s: bogus conversation function"),MODULE);
294 +    }
295 +  } else {
296 +    if (debug)
297 +      syslog(LOG_DEBUG, _("%s: no conversation function"),MODULE);
298 +  }
299 +  return (security_context_t) strdup(contextlist[0]);  
300 +}
301 +static const security_context_t 
302 +manual_context( pam_handle_t *pamh, char *user, int debug)
303 +{
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;
309 +      while (1) {
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')       
312 +       {
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))
316 +           {
317 +             context_free (new_context);
318 +             return NULL;
319 +           }
320 +         query_response(conv,_("role: "),&responses,debug);
321 +         if (context_role_set (new_context, responses[0].resp))
322 +           {
323 +             context_free (new_context);
324 +             return NULL;
325 +           }
326 +         query_response(conv,_("type: "),&responses,debug);
327 +         if (context_type_set (new_context, responses[0].resp))
328 +           {
329 +             context_free (new_context);
330 +             return NULL;
331 +           }
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);
336 +           return newcon;
337 +         }
338 +         else 
339 +           send_text(conv,_("Not a valid security context"),debug);
340 +       }
341 +       else {
342 +         return NULL;
343 +       }
344 +      }
345 +    } else {
346 +      if (debug)
347 +       syslog(LOG_DEBUG, _("%s: bogus conversation function"),MODULE);
348 +    }
349 +  } else {
350 +    if (debug)
351 +      syslog(LOG_DEBUG, _("%s: no conversation function"),MODULE);
352 +  }
353 +  return NULL;
354 +}
355 +
356 +static void security_restorelabel_tty(const char *tty,security_context_t context) {
357 +  char ttybuf[PATH_MAX];
358 +  const char *ptr;
359 +
360 +  if (context==NULL)
361 +    return;
362 +  
363 +  if(strncmp("/dev/", tty, 5))
364 +  {
365 +    snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty);
366 +    ptr = ttybuf;
367 +  }
368 +  else
369 +    ptr = tty;
370 +
371 +  if(!strncmp(tty, "/dev/pts", 8))
372 +    return;
373 +
374 +  if (setfilecon(ptr, context)) 
375 +    {
376 +      syslog(LOG_NOTICE, _("Warning!  Could not relabel %s with %s, not relabeling.\n"), ttybuf,context);
377 +    }
378 +  return;
379 +}
380 +
381 +static security_context_t security_label_tty(char *tty, security_context_t usercon) {
382 +  char ttybuf[PATH_MAX];
383 +  int status=0;
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 */
386 +  const char *ptr;
387 +  if(strncmp("/dev/", tty, 5))
388 +  {
389 +    snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty);
390 +    ptr = ttybuf;
391 +  }
392 +  else
393 +    ptr = tty;
394 +
395 +  if (getfilecon(ptr, &prev_context) < 0) 
396 +    {
397 +      syslog(LOG_NOTICE, _("Warning!  Could not get current context for %s, not relabeling."), ptr);
398 +      return NULL;
399 +    }  
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);
404 +    return NULL;
405 +  }
406 +  status=setfilecon(ptr,newdev_context);
407 +  freecon(newdev_context);
408 +  if (status)
409 +    {
410 +      syslog(LOG_NOTICE, _("Warning!  Could not relabel %s with %s, not relabeling."), ptr,newdev_context);
411 +      freecon(prev_context);
412 +      return NULL;
413 +    }
414 +  return prev_context;
415 +}
416 +
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;
422 +
423 +/* Tell the user that access has been granted. */
424 +static void
425 +verbose_message(pam_handle_t *pamh, char *msg, int debug)
426 +{
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);
437 +
438 +      message.msg = text;
439 +      if (debug)
440 +       syslog(LOG_DEBUG, MODULE ": %s", message.msg);
441 +      conv->conv(1, messages, &responses, conv->appdata_ptr);
442 +    } else {
443 +      if (debug)
444 +       syslog(LOG_DEBUG, _("%s: bogus conversation function"),MODULE);
445 +    }
446 +  } else {
447 +    if (debug)
448 +      syslog(LOG_DEBUG,_("%s: no conversation function"),MODULE);
449 +  }
450 +}
451 +
452 +PAM_EXTERN int
453 +pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
454 +{
455 +       /* Fail by default. */
456 +       return PAM_AUTH_ERR;
457 +}
458 +
459 +PAM_EXTERN int
460 +pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
461 +{
462 +       return PAM_SUCCESS;
463 +}
464 +
465 +PAM_EXTERN int
466 +pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
467 +{
468 +  int i, debug = 0, ttys=1,verbose=0,multiple=0;
469 +  int ret=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()) )
476 +    {
477 +      return PAM_SUCCESS;
478 +    }
479 +  for (i = 0; i < argc; i++) {
480 +    if (strcmp(argv[i], "debug") == 0) {
481 +      debug = 1;
482 +    }
483 +    if (strcmp(argv[i], "nottys") == 0) {
484 +      ttys = 0;
485 +    }
486 +    if (strcmp(argv[i], "verbose") == 0) {
487 +      verbose = 1;
488 +    }
489 +    if (strcmp(argv[i], "multiple") == 0) {
490 +      multiple = 1;
491 +    }
492 +  }
493 +
494 +  if (pam_get_item(pamh, PAM_USER, (const void**)&username) != PAM_SUCCESS) {
495 +    return PAM_AUTH_ERR;
496 +  }
497 +  num_contexts = get_ordered_context_list(username, 0, &contextlist);
498 +  if (num_contexts > 0) {
499 +    if (multiple) {
500 +      user_context = select_context(pamh,contextlist, debug);
501 +      freeconary(contextlist);
502 +      if (ret < 0) {
503 +       syslog (LOG_ERR,  _("%s:  query_user_context failed"), argv[0]);
504 +       return PAM_AUTH_ERR;
505 +      }
506 +    } else {
507 +      user_context = (security_context_t) strdup(contextlist[0]);
508 +      freeconary(contextlist);
509 +    }
510 +  } else {
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;
515 +    }
516 +  }
517 +  if (getexeccon(&prev_user_context)<0) {
518 +    prev_user_context=NULL;
519 +  }
520 +  if (ttys) {
521 +    /* Get the name of the terminal. */
522 +    if (pam_get_item(pamh, PAM_TTY, (const void**)&tty) != PAM_SUCCESS) {
523 +      tty = NULL;
524 +    }
525 +    if ((tty == NULL) || (strlen(tty) == 0)) {
526 +      tty = ttyname(STDIN_FILENO);
527 +      if ((tty == NULL) || (strlen(tty) == 0)) {
528 +       tty = ttyname(STDOUT_FILENO);
529 +      }
530 +      if ((tty == NULL) || (strlen(tty) == 0)) {
531 +       tty = ttyname(STDERR_FILENO);
532 +      }
533 +    }
534 +  }
535 +  if(ttys && tty && strncmp(tty, "NODEV", 5) ) {
536 +    ttyn=strdup(tty);
537 +    ttyn_context=security_label_tty(ttyn,user_context);
538 +  }
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);
545 +  }
546 +  if (ret) {
547 +    syslog(LOG_ERR, _("Error!  Unable to set %s executable context %s."),username, user_context);
548 +    freecon(user_context);
549 +    return PAM_AUTH_ERR;
550 +  } else {
551 +    if (debug)
552 +      syslog(LOG_DEBUG, _("%s: set %s security context to %s"),MODULE, username, user_context);
553 +  }
554 +  freecon(user_context);
555 +
556 +  return PAM_SUCCESS;
557 +}
558 +
559 +PAM_EXTERN int
560 +pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
561 +{
562 +  int i, debug = 0,status=0;
563 +  if (! (selinux_enabled ))
564 +    {
565 +      return PAM_SUCCESS;
566 +    }
567 +  /* Parse arguments. */
568 +  for (i = 0; i < argc; i++) {
569 +    if (strcmp(argv[i], "debug") == 0) {
570 +      debug = 1;
571 +    }
572 +  }
573 +
574 +  if (ttyn) {
575 +    security_restorelabel_tty(ttyn,ttyn_context);
576 +    freecon(ttyn_context);
577 +    free(ttyn);
578 +    ttyn=NULL;
579 +  }
580 +  status=setexeccon(prev_user_context);
581 +  freecon(prev_user_context);
582 +  if (status) {
583 +    syslog(LOG_ERR, _("Error!  Unable to set executable context %s."), prev_user_context);
584 +    return PAM_AUTH_ERR;
585 +  }
586 +
587 +  if (debug)
588 +    syslog(LOG_DEBUG, _("%s: setcontext back to orginal"),MODULE);
589 +
590 +  return PAM_SUCCESS;
591 +}
592 +
593 +#else /* PAM_SELINUX_MAIN */
594 +
595 +/************************************************************************
596 + *
597 + * All PAM code goes in this section.
598 + *
599 + ************************************************************************/
600 +
601 +#include <unistd.h>               /* for getuid(), exit(), getopt() */
602 +#include <signal.h>
603 +#include <sys/wait.h>            /* for wait() */
604 +
605 +#include <security/pam_appl.h>    /* for PAM functions */
606 +#include <security/pam_misc.h>    /* for misc_conv PAM utility function */
607 +
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);
612 +
613 +/* authenticate_via_pam()
614 + *
615 + * in:     user
616 + * out:    nothing
617 + * return: value   condition
618 + *         -----   ---------
619 + *           1     pam thinks that the user authenticated themselves properly
620 + *           0     otherwise
621 + *
622 + * this function uses pam to authenticate the user running this
623 + * program.  this is the only function in this program that makes pam
624 + * calls.
625 + *
626 + */
627 +
628 +int authenticate_via_pam( const char *user ,   pam_handle_t **pamh) {
629 +
630 +  struct pam_conv *conv;
631 +  int result = 0;    /* our result, set to 0 (not authenticated) by default */
632 +
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 = {
637 +    misc_conv,
638 +    NULL
639 +  };
640 +  conv = &pam_conversation;
641 +
642 +
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,
646 +                               user,
647 +                               conv,
648 +                               pamh ) ) {
649 +    fprintf( stderr, _("failed to initialize PAM\n") );
650 +    exit( -1 );
651 +  }
652 +
653 +  if( PAM_SUCCESS != pam_set_item(*pamh, PAM_RUSER, user))
654 +    {
655 +      fprintf( stderr, _("failed to pam_set_item()\n") );
656 +      exit( -1 );
657 +    }
658 +
659 +  /* Ask PAM to authenticate the user running this program */
660 +  if( PAM_SUCCESS == pam_authenticate(*pamh,0) ) {
661 +    result = 1;  /* user authenticated OK! */
662 +  }
663 +  pam_open_session(*pamh, 0);
664 +  return( result );
665 +
666 +} /* authenticate_via_pam() */
667 +
668 +int main(int argc, char **argv) {
669 +  pam_handle_t *pamh;
670 +  int childPid;
671 +  if (!authenticate_via_pam(argv[1],&pamh))
672 +    exit(-1);
673 +
674 +  childPid = fork();
675 +  if (childPid < 0) {
676 +    int errsv = errno;
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 );
682 +    exit(0);
683 +  }
684 +  if (childPid) {
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 );
696 +    exit(0);
697 +  }
698 +  argv[0]="/bin/sh";
699 +  argv[1]=NULL;
700 +  execv("/bin/sh",argv);
701 +  fprintf(stderr,"Failure\n");
702 +  return 0;
703 +}
704 +#endif
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
708 @@ -0,0 +1,35 @@
709 +.TH pam_selinux_check 8 2002/05/23 "Red Hat Linux" "System Administrator's Manual"
710 +.SH NAME
711 +pam_selinux_check \- login program to test pam_selinux_check
712 +.SH SYNOPSIS
713 +.B pam_selinux_check [user]
714 +.br
715 +
716 +.SH DESCRIPTION
717 +With no arguments,
718 +.B pam_selinux_check
719 +will prompt for user
720 +
721 +.SH OPTIONS
722 +.IP target_user
723 +The user to login as.
724 +
725 +.SH DIAGNOSTICS
726 +You must setup a /etc/pam.d/pam_selinux_check file, in order for the check to work.
727 +
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:
731 +
732 +.nf
733 +1: Authentication failure
734 +.fi
735 +
736 +.SH SEE ALSO
737 +pam_selinux(8)
738 +
739 +.SH BUGS
740 +Let's hope not, but if you find any, please email the author.  
741 +
742 +.SH 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
747 @@ -0,0 +1,43 @@
748 +/******************************************************************************
749 + * A module for Linux-PAM that will set the default security context after login 
750 + * via PAM.
751 + *
752 + * Copyright (c) 2003 Red Hat, Inc.
753 + * Written by Dan Walsh <dwalsh@redhat.com>
754 + *
755 + * Redistribution and use in source and binary forms, with or without
756 + * modification, are permitted provided that the following conditions
757 + * are met:
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.
767 + *
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.)
773 + *
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.
785 + *
786 + */
787 +
788 +#define PAM_SELINUX_MAIN 1
789 +#include "pam_selinux.c"
790 +
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
794 @@ -0,0 +1,15 @@
795 +This is pam_selinux, a module for setting the default security context after 
796 +login via PAM.
797 +
798 +Background:  SELinux provides a mechanism for allowing people to login with 
799 +different security contexts.
800 +
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.
806 +
807 +Dan Walsh <dwalsh@redhat.com>
808 +
809 +
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
813 @@ -26,6 +26,9 @@
814  
815  #include <fcntl.h>
816  #include <signal.h>
817 +#ifdef WITH_SELINUX
818 +#include <selinux/selinux.h>
819 +#endif
820  
821  #define LOCKFILE "/etc/.pwd.lock"
822  #define TIMEOUT 15
823 @@ -64,6 +67,28 @@
824         if (lockfd != -1)
825                 return -1;
826  
827 +#ifdef WITH_SELINUX
828 +       if(is_selinux_enabled())
829 +       {
830 +               lockfd = open(LOCKFILE, O_WRONLY);
831 +               if(lockfd == -1 && errno == ENOENT)
832 +               {
833 +                       security_context_t create_context;
834 +                       int rc;
835 +
836 +                       if(getfilecon("/etc/passwd", &create_context))
837 +                               return -1;
838 +                       rc = setfscreatecon(create_context);
839 +                       freecon(create_context);
840 +                       if(rc)
841 +                               return -1;
842 +                       lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
843 +                       if(setfscreatecon(NULL))
844 +                               return -1;
845 +               }
846 +       }
847 +       else
848 +#endif
849         lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
850         if (lockfd == -1)
851                 return -1;
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
855 @@ -9,10 +9,18 @@
856  modulesdir             = /lib/security
857  sbindir                        = /sbin
858  
859 +if SELINUX_PRESENT
860 +LIBSELINUX              = -lselinux
861 +LIBSELINUX_DEFS                = -DWITH_SELINUX=1
862 +else
863 +LIBSELINUX              =
864 +LIBSELINUX_DEFS                =
865 +endif
866 +
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)
872  
873  if DYNAMIC_MODULES
874  modules_LTLIBRARIES    = pam_unix.la
875 @@ -25,15 +33,15 @@
876  
877  if NSLLIB_PRESENT
878  if CRACKLIB_PRESENT
879 -pam_unix_la_LIBADD     = -lnsl -lcrack ../../pamcrypt/libpamcrypt.la
880 +pam_unix_la_LIBADD     = -lnsl -lcrack $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
881  else
882 -pam_unix_la_LIBADD     = -lnsl ../../pamcrypt/libpamcrypt.la
883 +pam_unix_la_LIBADD     = -lnsl $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
884  endif
885  else
886  if CRACKLIB_PRESENT
887 -pam_unix_la_LIBADD     = -lcrack ../../pamcrypt/libpamcrypt.la
888 +pam_unix_la_LIBADD     = -lcrack $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
889  else
890 -pam_unix_la_LIBADD     = ../../pamcrypt/libpamcrypt.la
891 +pam_unix_la_LIBADD     = $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
892  endif
893  endif
894  
895 @@ -42,7 +50,8 @@
896  sbin_PROGRAMS          = unix_chkpwd
897  
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
902  
903  EXTRA_DIST             = README CHANGELOG
904  
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
908 @@ -44,6 +44,15 @@
909  #include <pwd.h>
910  #include <shadow.h>
911  #include <time.h>              /* for time() */
912 +#include <linux/limits.h>
913 +#include <errno.h>
914 +#include <sys/wait.h>
915 +#ifdef WITH_SELINUX
916 +#include <selinux/selinux.h>
917 +#define SELINUX_ENABLED is_selinux_enabled()
918 +#else
919 +#define SELINUX_ENABLED 0
920 +#endif
921  
922  
923  #include "security/_pam_macros.h"
924 @@ -59,7 +68,110 @@
925  #endif                         /* LINUX_PAM */
926  
927  #include "support.h"
928 +struct spwd spwd;
929   
930 +struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user)
931 +{
932 +  int retval=0, child, fds[2];
933 +  void (*sighandler)(int) = NULL;
934 +  D(("running verify_binary"));
935 +
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));
940 +    return NULL;
941 +  }
942 +  D(("called."));
943 +  
944 +  if (off(UNIX_NOREAP, ctrl)) {
945 +    /*
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.
949 +     *
950 +     * The "noreap" module argument is provided so that the admin can
951 +     * override this behavior.
952 +     */
953 +    sighandler = signal(SIGCHLD, SIG_DFL);
954 +  }
955 +
956 +  /* fork */
957 +  child = fork();
958 +  if (child == 0) {
959 +    int i=0;
960 +    struct rlimit rlim;
961 +    static char *envp[] = { NULL };
962 +    char *args[] = { NULL, NULL, NULL, NULL };
963 +
964 +    close(0); close(1);
965 +    /* reopen stdin as pipe */
966 +    close(fds[0]);
967 +    dup2(fds[1], STDOUT_FILENO);
968 +    
969 +    /* XXX - should really tidy up PAM here too */
970 +    
971 +    if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
972 +      for (i=2; i < rlim.rlim_max; i++) {
973 +       if (fds[1] != i) {
974 +         close(i);
975 +       }
976 +      }        
977 +    }
978 +    /* exec binary helper */
979 +    args[0] = x_strdup(CHKPWD_HELPER);
980 +    args[1] = x_strdup(user);
981 +    args[2] = x_strdup("verify");
982 +    
983 +    execve(CHKPWD_HELPER, args, envp);
984 +    
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);
989 +  } else { 
990 +    if (child > 0) {
991 +      char buf[1024];
992 +      int rc=0;
993 +      rc = read(fds[0], buf, sizeof(buf) - 1);
994 +      if(rc > 0)
995 +       {
996 +         buf[rc] = '\0';
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 */
1004 +       }               
1005 +      else {
1006 +       _log_err(LOG_ERR, pamh, " ERROR %d:%s \n",rc, strerror(errno));
1007 +      }
1008 +      close(fds[1]);
1009 +      close(fds[0]);
1010 +      rc=waitpid(child, &retval, 0);  /* wait for helper to complete */
1011 +      if (rc<0) {
1012 +       _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
1013 +       retval = PAM_AUTH_ERR;
1014 +      } else {
1015 +       retval = WEXITSTATUS(retval);
1016 +      }
1017 +    } else {
1018 +      D(("fork failed"));
1019 +      close(fds[0]);close(fds[1]);
1020 +      retval = PAM_AUTH_ERR;
1021 +    }
1022 +  }
1023 +  if (sighandler != NULL) {
1024 +    (void) signal(SIGCHLD, sighandler);   /* restore old signal handler */
1025 +  }
1026 +  D(("Returning %d",retval));
1027 +  if (retval != PAM_SUCCESS) {
1028 +    return NULL;
1029 +  } 
1030 +  return &spwd;
1031 +}      
1032  /*
1033   * PAM framework looks for this entry-point to pass control to the
1034   * account management module.
1035 @@ -128,6 +240,9 @@
1036                 return PAM_SUCCESS;
1037         }
1038  
1039 +       if (!spent && SELINUX_ENABLED ) 
1040 +           spent = _unix_run_verify_binary(pamh, ctrl, uname);
1041 +
1042         if (!spent)
1043                 return PAM_AUTHINFO_UNAVAIL;    /* Couldn't get username from shadow */
1044  
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
1048 @@ -56,7 +56,18 @@
1049  #include <rpc/rpc.h>
1050  #include <rpcsvc/yp_prot.h>
1051  #include <rpcsvc/ypclnt.h>
1052 -
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())
1061 +#else
1062 +#define SELINUX_ENABLED 0
1063 +#endif
1064 +    
1065  #ifdef HAVE_CRACK_H
1066  #include <crack.h>
1067  #endif
1068 @@ -260,6 +271,97 @@
1069         return master;
1070  }
1071  
1072 +static int _unix_run_shadow_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user, const char *fromwhat, const char *towhat)
1073 +{
1074 +    int retval, child, fds[2];
1075 +    void (*sighandler)(int) = NULL;
1076 +
1077 +    D(("called."));
1078 +    /* create a pipe for the password */
1079 +    if (pipe(fds) != 0) {
1080 +       D(("could not make pipe"));
1081 +       return PAM_AUTH_ERR;
1082 +    }
1083 +
1084 +    if (off(UNIX_NOREAP, ctrl)) {
1085 +       /*
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.
1089 +        *
1090 +        * The "noreap" module argument is provided so that the admin can
1091 +        * override this behavior.
1092 +        */
1093 +       sighandler = signal(SIGCHLD, SIG_DFL);
1094 +    }
1095 +
1096 +    /* fork */
1097 +    child = fork();
1098 +    if (child == 0) {
1099 +        int i=0;
1100 +        struct rlimit rlim;
1101 +       static char *envp[] = { NULL };
1102 +       char *args[] = { NULL, NULL, NULL, NULL };
1103 +
1104 +       /* XXX - should really tidy up PAM here too */
1105 +
1106 +       close(0); close(1);
1107 +       /* reopen stdin as pipe */
1108 +       close(fds[1]);
1109 +       dup2(fds[0], STDIN_FILENO);
1110 +
1111 +       if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
1112 +         for (i=2; i < rlim.rlim_max; i++) {
1113 +               if (fds[0] != i)
1114 +                  close(i);
1115 +         }     
1116 +       }
1117 +       /* exec binary helper */
1118 +       args[0] = x_strdup(CHKPWD_HELPER);
1119 +       args[1] = x_strdup(user);
1120 +       args[2] = x_strdup("shadow");
1121 +
1122 +       execve(CHKPWD_HELPER, args, envp);
1123 +
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 */
1130 +        int rc=0;
1131 +       if (fromwhat) 
1132 +         write(fds[1], fromwhat, strlen(fromwhat)+1);
1133 +       else
1134 +         write(fds[1], "", 1);
1135 +       if (towhat) {
1136 +         write(fds[1], towhat, strlen(towhat)+1);
1137 +       }
1138 +       else
1139 +         write(fds[1], "", 1);
1140 +
1141 +       close(fds[0]);       /* close here to avoid possible SIGPIPE above */
1142 +       close(fds[1]);
1143 +       rc=waitpid(child, &retval, 0);  /* wait for helper to complete */
1144 +       if (rc<0) {
1145 +         _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
1146 +         retval = PAM_AUTH_ERR;
1147 +       } else {
1148 +         retval = WEXITSTATUS(retval);
1149 +       }
1150 +    } else {
1151 +       D(("fork failed"));
1152 +       close(fds[0]);
1153 +       close(fds[1]);
1154 +       retval = PAM_AUTH_ERR;
1155 +    }
1156 +
1157 +    if (sighandler != NULL) {
1158 +        (void) signal(SIGCHLD, sighandler);   /* restore old signal handler */
1159 +    }
1160 +
1161 +    return retval;
1162 +}
1163  static int check_old_password(const char *forwho, const char *newpass)
1164  {
1165         static char buf[16384];
1166 @@ -318,16 +420,41 @@
1167      }
1168  
1169         oldmask = umask(077);
1170 +       
1171 +       if (SELINUX_ENABLED) {
1172 +               security_context_t passwd_context = NULL;
1173 +               
1174 +               if (getfilecon("/etc/passwd",&passwd_context) < 0) {
1175 +                       return PAM_AUTHTOK_ERR;
1176 +               }
1177 +               
1178 +               if (getfscreatecon(&prev_context)<0) {
1179 +                       freecon(passwd_context);
1180 +                       return PAM_AUTHTOK_ERR;
1181 +               }
1182 +               
1183 +               if (setfscreatecon(passwd_context)) {
1184 +                       freecon(passwd_context);
1185 +                       freecon(prev_context);
1186 +                       return PAM_AUTHTOK_ERR;
1187 +               }
1188 +               
1189 +               freecon(passwd_context);
1190 +       }
1191 +
1192         pwfile = fopen(OPW_TMPFILE, "w");
1193         umask(oldmask);
1194 -    if (pwfile == NULL) {
1195 -               return PAM_AUTHTOK_ERR;
1196 -    }
1197 +    
1198 +       if (pwfile == NULL) {
1199 +           err = 1;
1200 +           goto done;
1201 +       }
1202  
1203         opwfile = fopen(OLD_PASSWORDS_FILE, "r");
1204         if (opwfile == NULL) {
1205 -               fclose(pwfile);
1206 -               return PAM_AUTHTOK_ERR;
1207 +               fclose(pwfile);
1208 +               err=1;
1209 +               goto done;
1210         }
1211  
1212         chown(OPW_TMPFILE, 0, 0);
1213 @@ -388,8 +515,20 @@
1214                 err = 1;
1215         }
1216  
1217 -       if (!err) {
1218 +done:
1219 +       if (!err)
1220                 rename(OPW_TMPFILE, OLD_PASSWORDS_FILE);
1221 +#ifdef WITH_SELINUX
1222 +       if (SELINUX_ENABLED) {
1223 +           if (setfscreatecon(prev_context)) {
1224 +               err = 1;
1225 +           }
1226 +           if (prev_context)
1227 +               freecon(prev_context);
1228 +           prev_context=NULL;
1229 +       }
1230 +#endif
1231 +       if (!err) {
1232                 return PAM_SUCCESS;
1233         } else {
1234                 unlink(OPW_TMPFILE);
1235 @@ -406,16 +545,36 @@
1236         int oldmask;
1237  
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;
1244 +           };
1245 +           if (getfscreatecon(&prev_context)<0) {
1246 +               freecon(passwd_context);
1247 +               return PAM_AUTHTOK_ERR;
1248 +           }
1249 +           if (setfscreatecon(passwd_context)) {
1250 +               freecon(passwd_context);
1251 +               freecon(prev_context);
1252 +               return PAM_AUTHTOK_ERR;
1253 +           }
1254 +           freecon(passwd_context);
1255 +       }
1256 +#endif
1257         pwfile = fopen(PW_TMPFILE, "w");
1258         umask(oldmask);
1259 -    if (pwfile == NULL) {
1260 -               return PAM_AUTHTOK_ERR;
1261 -    }
1262 +       if (pwfile == NULL) {
1263 +               err=1;
1264 +               goto done;
1265 +       }
1266  
1267         opwfile = fopen("/etc/passwd", "r");
1268         if (opwfile == NULL) {
1269 -               fclose(pwfile);
1270 -               return PAM_AUTHTOK_ERR;
1271 +               fclose(pwfile);       
1272 +               err = 1;
1273 +               goto done;
1274         }
1275  
1276         chown(PW_TMPFILE, 0, 0);
1277 @@ -447,9 +606,22 @@
1278                 err = 1;
1279         }
1280  
1281 +done:
1282         if (!err) {
1283                 rename(PW_TMPFILE, "/etc/passwd");
1284                 _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
1285 +       }
1286 +#ifdef WITH_SELINUX
1287 +       if (SELINUX_ENABLED) {
1288 +           if (setfscreatecon(prev_context)) {
1289 +               err = 1;
1290 +           }
1291 +           if (prev_context)
1292 +               freecon(prev_context);
1293 +           prev_context=NULL;
1294 +       }
1295 +#endif
1296 +       if (!err) {
1297                 return PAM_SUCCESS;
1298         } else {
1299                 unlink(PW_TMPFILE);
1300 @@ -465,20 +637,43 @@
1301         int oldmask;
1302  
1303         spwdent = getspnam(forwho);
1304 -    if (spwdent == NULL) {
1305 -               return PAM_USER_UNKNOWN;
1306 -    }
1307 +
1308 +       if (spwdent == NULL) {
1309 +           return PAM_USER_UNKNOWN;
1310 +       }
1311 +       
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;
1318 +           };
1319 +           if (getfscreatecon(&prev_context)<0) {
1320 +               freecon(shadow_context);
1321 +               return PAM_AUTHTOK_ERR;
1322 +           }
1323 +           if (setfscreatecon(shadow_context)) {
1324 +               freecon(shadow_context);
1325 +               freecon(prev_context);
1326 +               return PAM_AUTHTOK_ERR;
1327 +           }
1328 +           freecon(shadow_context);
1329 +       }
1330 +#endif
1331         pwfile = fopen(SH_TMPFILE, "w");
1332         umask(oldmask);
1333 -    if (pwfile == NULL) {
1334 -               return PAM_AUTHTOK_ERR;
1335 -    }
1336 +       
1337 +       if (pwfile == NULL) {
1338 +           err = 1;
1339 +           goto done;
1340 +       }
1341  
1342         opwfile = fopen("/etc/shadow", "r");
1343         if (opwfile == NULL) {
1344                 fclose(pwfile);
1345 -               return PAM_AUTHTOK_ERR;
1346 +               err = 1;
1347 +               goto done;
1348         }
1349  
1350         chown(SH_TMPFILE, 0, 0);
1351 @@ -508,8 +703,22 @@
1352                 err = 1;
1353         }
1354  
1355 +done:
1356         if (!err) {
1357                 rename(SH_TMPFILE, "/etc/shadow");
1358 +       }
1359 +#ifdef WITH_SELINUX
1360 +       if (SELINUX_ENABLED) {
1361 +           if (setfscreatecon(prev_context)) {
1362 +               err = 1;
1363 +           }
1364 +           if (prev_context)
1365 +               freecon(prev_context);
1366 +           prev_context=NULL;
1367 +       }
1368 +#endif
1369 +    
1370 +       if (!err) {
1371                 return PAM_SUCCESS;
1372         } else {
1373                 unlink(SH_TMPFILE);
1374 @@ -600,6 +809,8 @@
1375         }
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");
1382         } else {
1383 @@ -609,7 +820,7 @@
1384         return retval;
1385  }
1386  
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)
1389  {
1390         struct passwd *pwd = NULL;      /* Password and shadow password */
1391         struct spwd *spwdent = NULL;    /* file entries for the user */
1392 @@ -630,6 +841,8 @@
1393                 spwdent = getspnam(user);
1394                 endspent();
1395  
1396 +               if (spwdent == NULL && SELINUX_ENABLED ) 
1397 +                   spwdent = _unix_run_verify_binary(pamh, ctrl, user);
1398                 if (spwdent == NULL)
1399                         return PAM_AUTHINFO_UNAVAIL;
1400         } else {
1401 @@ -877,7 +1090,7 @@
1402                         _log_err(LOG_CRIT, pamh,
1403                                  "failed to set PAM_OLDAUTHTOK");
1404                 }
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 @@
1411  #endif
1412                         return retval;
1413                 }
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");
1418  #ifdef USE_LCKPWDF
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
1422 @@ -13,11 +13,18 @@
1423  #include <pwd.h>
1424  #include <shadow.h>
1425  #include <limits.h>
1426 +#include <linux/limits.h>
1427  #include <utmp.h>
1428  #include <errno.h>
1429  #include <crypt.h>
1430  #include <signal.h>
1431 -
1432 +#ifdef WITH_SELINUX
1433 +#include <selinux/selinux.h>
1434 +#define SELINUX_ENABLED is_selinux_enabled()
1435 +#else
1436 +#define SELINUX_ENABLED 0
1437 +#endif
1438 +    
1439  #include "security/_pam_macros.h"
1440  #include "security/pam_modules.h"
1441  
1442 @@ -464,18 +471,32 @@
1443      /* fork */
1444      child = fork();
1445      if (child == 0) {
1446 +        int i=0;
1447 +        struct rlimit rlim;
1448         static char *envp[] = { NULL };
1449 -       char *args[] = { NULL, NULL, NULL };
1450 +       char *args[] = { NULL, NULL, NULL, NULL };
1451  
1452         /* XXX - should really tidy up PAM here too */
1453  
1454 +       close(0); close(1);
1455         /* reopen stdin as pipe */
1456         close(fds[1]);
1457         dup2(fds[0], STDIN_FILENO);
1458  
1459 +       if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
1460 +         for (i=2; i < rlim.rlim_max; i++) {
1461 +               if (fds[0] != i)
1462 +                  close(i);
1463 +         }     
1464 +       }
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");
1470 +       } else {
1471 +         args[2]=x_strdup("nonull");
1472 +       }
1473  
1474         execve(CHKPWD_HELPER, args, envp);
1475  
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);
1482 -       } else {
1483 -           write(fds[1], "nonull\0\0", 8);
1484 -       }
1485 +        int rc=0;
1486         if (passwd != NULL) {            /* send the password to the child */
1487             write(fds[1], passwd, strlen(passwd)+1);
1488             passwd = NULL;
1489 @@ -498,10 +515,17 @@
1490         }
1491         close(fds[0]);       /* close here to avoid possible SIGPIPE above */
1492         close(fds[1]);
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 */
1496 +       if (rc<0) {
1497 +         _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
1498 +         retval = PAM_AUTH_ERR;
1499 +       } else {
1500 +         retval = WEXITSTATUS(retval);
1501 +       }
1502      } else {
1503         D(("fork failed"));
1504 +       close(fds[0]);
1505 +       close(fds[1]);
1506         retval = PAM_AUTH_ERR;
1507      }
1508  
1509 @@ -523,6 +547,7 @@
1510         char *data_name;
1511         int retval;
1512  
1513 +
1514         D(("called"));
1515  
1516  #ifdef HAVE_PAM_FAIL_DELAY
1517 @@ -589,7 +614,7 @@
1518  
1519         retval = PAM_SUCCESS;
1520         if (pwd == NULL || salt == NULL || !strcmp(salt, "x")) {
1521 -               if (geteuid()) {
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
1529 @@ -147,5 +147,6 @@
1530                         ,const char *data_name
1531                         ,const char **pass);
1532  
1533 +extern struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user);
1534  #endif /* _PAM_UNIX_SUPPORT_H */
1535  
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
1539 @@ -27,13 +27,24 @@
1540  #include <syslog.h>
1541  #include <unistd.h>
1542  #include <sys/types.h>
1543 +#include <sys/stat.h>
1544  #include <pwd.h>
1545  #include <shadow.h>
1546  #include <signal.h>
1547  #include <crypt.h>
1548 -
1549 +#include <time.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;
1555 +#else
1556 +#define SELINUX_ENABLED 0
1557 +#endif
1558 +    
1559  #define MAXPASS                200     /* the maximum length of a password */
1560  
1561 +#include <security/_pam_types.h>
1562  #include "security/_pam_macros.h"
1563  
1564  #include "pam_crypt.h"
1565 @@ -86,6 +97,33 @@
1566         (void) sigaction(SIGQUIT, &action, NULL);
1567  }
1568  
1569 +static int _verify_account(const char * const uname)
1570 +{
1571 +       struct spwd *spent;
1572 +       struct passwd *pwent;
1573 +   
1574 +       pwent = getpwnam(uname);
1575 +       if (!pwent) {
1576 +           _log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname);
1577 +           return PAM_USER_UNKNOWN;
1578 +       }
1579 +  
1580 +       spent = getspnam( uname );
1581 +       if (!spent) {
1582 +           _log_err(LOG_ALERT, "could not get username from shadow (%s))", uname);
1583 +           return PAM_AUTHINFO_UNAVAIL;    /* Couldn't get username from shadow */
1584 +       }
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 */
1592 +       
1593 +       return PAM_SUCCESS;
1594 +}
1595 +
1596  static int _unix_verify_password(const char *name, const char *p, int opt)
1597  {
1598         struct passwd *pwd = NULL;
1599 @@ -223,11 +261,171 @@
1600         return username;
1601  }
1602  
1603 + #define SH_TMPFILE            "/etc/nshadow"
1604 + static int _update_shadow(const char *forwho)
1605 + {
1606 +     struct spwd *spwdent = NULL, *stmpent = NULL;
1607 +     FILE *pwfile, *opwfile;
1608 +     int err = 1;
1609 +     int oldmask;
1610 +     struct stat st;
1611 +     char pass[MAXPASS + 1];
1612 +     char towhat[MAXPASS + 1];
1613 +     int npass=0;
1614 +
1615 +     /* read the password from stdin (a pipe from the pam_unix module) */
1616 +
1617 +     npass = read(STDIN_FILENO, pass, MAXPASS);
1618 +
1619 +     if (npass < 0) {  /* is it a valid password? */
1620 +
1621 +       _log_err(LOG_DEBUG, "no password supplied");
1622 +       return PAM_AUTHTOK_ERR;
1623 +
1624 +     } else if (npass >= MAXPASS) {
1625 +
1626 +       _log_err(LOG_DEBUG, "password too long");
1627 +       return PAM_AUTHTOK_ERR;
1628 +
1629 +     } else {
1630 +       /* does pass agree with the official one? */
1631 +       int retval=0;
1632 +       pass[npass] = '\0';     /* NUL terminate */
1633 +       retval = _unix_verify_password(forwho, pass, 0);
1634 +       if (retval != PAM_SUCCESS) {
1635 +       return retval;
1636 +       }
1637 +     }
1638 +
1639 +     /* read the password from stdin (a pipe from the pam_unix module) */
1640 +
1641 +     npass = read(STDIN_FILENO, towhat, MAXPASS);
1642 +
1643 +     if (npass < 0) {  /* is it a valid password? */
1644 +
1645 +       _log_err(LOG_DEBUG, "no new password supplied");
1646 +       return PAM_AUTHTOK_ERR;
1647 +
1648 +     } else if (npass >= MAXPASS) {
1649 +
1650 +       _log_err(LOG_DEBUG, "new password too long");
1651 +       return PAM_AUTHTOK_ERR;
1652 +
1653 +     }
1654 +
1655 +     towhat[npass] = '\0';     /* NUL terminate */
1656 +     spwdent = getspnam(forwho);
1657 +     if (spwdent == NULL) {
1658 +       return PAM_USER_UNKNOWN;
1659 +     }
1660 +     oldmask = umask(077);
1661 +
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;
1667 +       };
1668 +       if (getfscreatecon(&prev_context)<0) {
1669 +       freecon(shadow_context);
1670 +       return PAM_AUTHTOK_ERR;
1671 +       }
1672 +       if (setfscreatecon(shadow_context)) {
1673 +       freecon(shadow_context);
1674 +       freecon(prev_context);
1675 +       return PAM_AUTHTOK_ERR;
1676 +       }
1677 +       freecon(shadow_context);
1678 +     }
1679 + #endif
1680 +     pwfile = fopen(SH_TMPFILE, "w");
1681 +     umask(oldmask);
1682 +     if (pwfile == NULL) {
1683 +       err = 1;
1684 +       goto done;
1685 +     }
1686 +
1687 +     opwfile = fopen("/etc/shadow", "r");
1688 +     if (opwfile == NULL) {
1689 +       fclose(pwfile);
1690 +       err = 1;
1691 +       goto done;
1692 +     }
1693 +
1694 +     if (fstat(fileno(opwfile), &st) == -1) {
1695 +       fclose(opwfile);
1696 +       fclose(pwfile);
1697 +       err = 1;
1698 +       goto done;
1699 +     }
1700 +
1701 +     if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
1702 +       fclose(opwfile);
1703 +       fclose(pwfile);
1704 +       err = 1;
1705 +       goto done;
1706 +     }
1707 +     if (fchmod(fileno(pwfile), st.st_mode) == -1) {
1708 +       fclose(opwfile);
1709 +       fclose(pwfile);
1710 +       err = 1;
1711 +       goto done;
1712 +     }
1713 +     stmpent = fgetspent(opwfile);
1714 +     while (stmpent) {
1715 +
1716 +       if (!strcmp(stmpent->sp_namp, forwho)) {
1717 +           stmpent->sp_pwdp = towhat;
1718 +           stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
1719 +           err = 0;
1720 +           D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
1721 +       }
1722 +
1723 +       if (putspent(stmpent, pwfile)) {
1724 +           D(("error writing entry to shadow file: %s\n", strerror(errno)));
1725 +           err = 1;
1726 +           break;
1727 +       }
1728 +
1729 +       stmpent = fgetspent(opwfile);
1730 +     }
1731 +     fclose(opwfile);
1732 +
1733 +     if (fclose(pwfile)) {
1734 +       D(("error writing entries to shadow file: %s\n", strerror(errno)));
1735 +       err = 1;
1736 +     }
1737 +
1738 +  done:
1739 +     if (!err) {
1740 +       rename(SH_TMPFILE, "/etc/shadow");
1741 +     }
1742 +
1743 + #ifdef WITH_SELINUX
1744 +     if (SELINUX_ENABLED) {
1745 +       if (setfscreatecon(prev_context)) {
1746 +       err = 1;
1747 +       }
1748 +       if (prev_context)
1749 +       freecon(prev_context);
1750 +       prev_context=NULL;
1751 +     }
1752 + #endif
1753 +
1754 +     if (!err) {
1755 +       return PAM_SUCCESS;
1756 +     } else {
1757 +       unlink(SH_TMPFILE);
1758 +       return PAM_AUTHTOK_ERR;
1759 +     }
1760 + }
1761 +
1762 +
1763  int main(int argc, char *argv[])
1764  {
1765         char pass[MAXPASS + 1];
1766 -       char option[8];
1767         int npass, opt;
1768 +       char *option;
1769         int force_failure = 0;
1770         int retval = UNIX_FAILED;
1771         char *user;
1772 @@ -246,8 +444,7 @@
1773          * account).
1774          */
1775  
1776 -       if (isatty(STDIN_FILENO)) {
1777 -
1778 +       if (isatty(STDIN_FILENO) || argc != 3 ) {
1779                 _log_err(LOG_NOTICE
1780                       ,"inappropriate use of Unix helper binary [UID=%d]"
1781                          ,getuid());
1782 @@ -258,19 +455,43 @@
1783                 return UNIX_FAILED;
1784         }
1785  
1786 -       /*
1787 -        * determine the current user's name is
1788 -        */
1789 -       user = getuidname(getuid());
1790 -       if (argc == 2) {
1791 -           /* if the caller specifies the username, verify that user
1792 -              matches it */
1793 -           if (strcmp(user, argv[1])) {
1794 -               force_failure = 1;
1795 -           }
1796 -       }
1797 +       /*
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
1802 +        * for root.
1803 +         */
1804 +       if (SELINUX_ENABLED) {
1805 +         user=argv[1];
1806 +       }
1807 +       else {
1808 +         user = getuidname(getuid());
1809 +         /* if the caller specifies the username, verify that user
1810 +            matches it */
1811 +         if (strcmp(user, argv[1])) {
1812 +           return UNIX_FAILED;
1813 +         }
1814 +        }
1815 +
1816 +       option=argv[2];
1817 +
1818 +       if (strncmp(argv[2], "verify", 8) == 0) {
1819 +         /* Get the account information from the shadow file */
1820 +         return _verify_account(argv[1]);
1821 +       }
1822 +
1823 +       if (strncmp(option, "shadow", 8) == 0) {
1824 +         /* Attempting to change the password */
1825 +         return _update_shadow(argv[1]);
1826 +        }
1827 +       /* read the nullok/nonull option */
1828 +       if (strncmp(option, "nullok", 8) == 0)
1829 +         nullok = 1;
1830 +       else
1831 +         nullok = 0;
1832  
1833 -       /* read the nullok/nonull option */
1834 +        /* read the password from stdin (a pipe from the pam_unix module) */
1835  
1836         npass = read(STDIN_FILENO, option, 8);
1837  
This page took 0.236341 seconds and 4 git commands to generate.