]> git.pld-linux.org Git - packages/pam.git/blob - pam-selinux-1.patch
am/ac update
[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:24:11.528531840 +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, libselinux_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(LIBSELINUX_PRESENT, test x$libselinux_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:17:34.973817320 +0100
44 @@ -0,0 +1,61 @@
45 +## Process this file with automake to produce Makefile.in
46 +
47 +@SET_MAKE@
48 +
49 +if LIBSELINUX_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_seelinux_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 $(DYNAMIC)
75 +pam_selinuc_check_la_CFLAGS    = -I$(top_srcdir)/include $(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 LIBSELINX_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:20:17.576098016 +0100
855 @@ -9,6 +9,14 @@
856  modulesdir             = /lib/security
857  sbindir                        = /sbin
858  
859 +if LIBSELINUX_PRESENT
860 +LIBSELINUX              = -lselinux
861 +DEFS                   = -DWITH_SELINUX=1
862 +else
863 +LIBSELINUX              =
864 +DEFS           =
865 +endif
866 +
867  AM_CPPFLAGS = -DCHKPWD_HELPER=\"$(sbindir)/$(sbin_PROGRAMS)\" \
868                           -I$(top_srcdir)/include \
869                           -I$(top_srcdir)/pamcrypt/include
870 @@ -25,15 +33,15 @@
871  
872  if NSLLIB_PRESENT
873  if CRACKLIB_PRESENT
874 -pam_unix_la_LIBADD     = -lnsl -lcrack ../../pamcrypt/libpamcrypt.la
875 +pam_unix_la_LIBADD     = -lnsl -lcrack $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
876  else
877 -pam_unix_la_LIBADD     = -lnsl ../../pamcrypt/libpamcrypt.la
878 +pam_unix_la_LIBADD     = -lnsl $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
879  endif
880  else
881  if CRACKLIB_PRESENT
882 -pam_unix_la_LIBADD     = -lcrack ../../pamcrypt/libpamcrypt.la
883 +pam_unix_la_LIBADD     = -lcrack $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
884  else
885 -pam_unix_la_LIBADD     = ../../pamcrypt/libpamcrypt.la
886 +pam_unix_la_LIBADD     = $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
887  endif
888  endif
889  
890 @@ -42,7 +50,7 @@
891  sbin_PROGRAMS          = unix_chkpwd
892  
893  unix_chkpwd_SOURCES    = unix_chkpwd.c
894 -unix_chkpwd_LDADD      = ../../pamcrypt/libpamcrypt.la
895 +unix_chkpwd_LDADD      = $(LIBSELINUX) ../../pamcrypt/libpamcrypt.la
896  
897  EXTRA_DIST             = README CHANGELOG
898  
899 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
900 --- pam-pld-0.77.3.org/modules/pam_unix/pam_unix_acct.c 2003-12-27 01:14:07.000000000 +0100
901 +++ pam-pld-0.77.3/modules/pam_unix/pam_unix_acct.c     2003-12-27 01:14:20.000000000 +0100
902 @@ -44,6 +44,15 @@
903  #include <pwd.h>
904  #include <shadow.h>
905  #include <time.h>              /* for time() */
906 +#include <linux/limits.h>
907 +#include <errno.h>
908 +#include <sys/wait.h>
909 +#ifdef WITH_SELINUX
910 +#include <selinux/selinux.h>
911 +#define SELINUX_ENABLED is_selinux_enabled()
912 +#else
913 +#define SELINUX_ENABLED 0
914 +#endif
915  
916  
917  #include "security/_pam_macros.h"
918 @@ -59,7 +68,110 @@
919  #endif                         /* LINUX_PAM */
920  
921  #include "support.h"
922 +struct spwd spwd;
923   
924 +struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user)
925 +{
926 +  int retval=0, child, fds[2];
927 +  void (*sighandler)(int) = NULL;
928 +  D(("running verify_binary"));
929 +
930 +  /* create a pipe for the messages */
931 +  if (pipe(fds) != 0) {
932 +    D(("could not make pipe"));
933 +    _log_err(LOG_ERR, pamh, "Could not make pipe %s",strerror(errno));
934 +    return NULL;
935 +  }
936 +  D(("called."));
937 +  
938 +  if (off(UNIX_NOREAP, ctrl)) {
939 +    /*
940 +     * This code arranges that the demise of the child does not cause
941 +     * the application to receive a signal it is not expecting - which
942 +     * may kill the application or worse.
943 +     *
944 +     * The "noreap" module argument is provided so that the admin can
945 +     * override this behavior.
946 +     */
947 +    sighandler = signal(SIGCHLD, SIG_DFL);
948 +  }
949 +
950 +  /* fork */
951 +  child = fork();
952 +  if (child == 0) {
953 +    int i=0;
954 +    struct rlimit rlim;
955 +    static char *envp[] = { NULL };
956 +    char *args[] = { NULL, NULL, NULL, NULL };
957 +
958 +    close(0); close(1);
959 +    /* reopen stdin as pipe */
960 +    close(fds[0]);
961 +    dup2(fds[1], STDOUT_FILENO);
962 +    
963 +    /* XXX - should really tidy up PAM here too */
964 +    
965 +    if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
966 +      for (i=2; i < rlim.rlim_max; i++) {
967 +       if (fds[1] != i) {
968 +         close(i);
969 +       }
970 +      }        
971 +    }
972 +    /* exec binary helper */
973 +    args[0] = x_strdup(CHKPWD_HELPER);
974 +    args[1] = x_strdup(user);
975 +    args[2] = x_strdup("verify");
976 +    
977 +    execve(CHKPWD_HELPER, args, envp);
978 +    
979 +    _log_err(LOG_ERR, pamh, "execve failed: %s",strerror(errno));
980 +    /* should not get here: exit with error */
981 +    D(("helper binary is not available"));
982 +    exit(PAM_AUTHINFO_UNAVAIL);
983 +  } else { 
984 +    if (child > 0) {
985 +      char buf[1024];
986 +      int rc=0;
987 +      rc = read(fds[0], buf, sizeof(buf) - 1);
988 +      if(rc > 0)
989 +       {
990 +         buf[rc] = '\0';
991 +         sscanf(buf,"%ld:%ld:%ld:%ld:%ld:%ld",
992 +                &spwd.sp_lstchg, /* last password change */
993 +                 &spwd.sp_min, /* days until change allowed. */
994 +                 &spwd.sp_max, /* days before change required */
995 +                 &spwd.sp_warn, /* days warning for expiration */
996 +                 &spwd.sp_inact, /* days before account inactive */
997 +                 &spwd.sp_expire); /* date when account expires */
998 +       }               
999 +      else {
1000 +       _log_err(LOG_ERR, pamh, " ERROR %d:%s \n",rc, strerror(errno));
1001 +      }
1002 +      close(fds[1]);
1003 +      close(fds[0]);
1004 +      rc=waitpid(child, &retval, 0);  /* wait for helper to complete */
1005 +      if (rc<0) {
1006 +       _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
1007 +       retval = PAM_AUTH_ERR;
1008 +      } else {
1009 +       retval = WEXITSTATUS(retval);
1010 +      }
1011 +    } else {
1012 +      D(("fork failed"));
1013 +      close(fds[0]);close(fds[1]);
1014 +      retval = PAM_AUTH_ERR;
1015 +    }
1016 +  }
1017 +  if (sighandler != NULL) {
1018 +    (void) signal(SIGCHLD, sighandler);   /* restore old signal handler */
1019 +  }
1020 +  D(("Returning %d",retval));
1021 +  if (retval != PAM_SUCCESS) {
1022 +    return NULL;
1023 +  } 
1024 +  return &spwd;
1025 +}      
1026  /*
1027   * PAM framework looks for this entry-point to pass control to the
1028   * account management module.
1029 @@ -128,6 +240,9 @@
1030                 return PAM_SUCCESS;
1031         }
1032  
1033 +       if (!spent && SELINUX_ENABLED ) 
1034 +           spent = _unix_run_verify_binary(pamh, ctrl, uname);
1035 +
1036         if (!spent)
1037                 return PAM_AUTHINFO_UNAVAIL;    /* Couldn't get username from shadow */
1038  
1039 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
1040 --- pam-pld-0.77.3.org/modules/pam_unix/pam_unix_passwd.c       2003-12-27 01:14:07.000000000 +0100
1041 +++ pam-pld-0.77.3/modules/pam_unix/pam_unix_passwd.c   2003-12-27 03:09:39.984026744 +0100
1042 @@ -56,7 +56,18 @@
1043  #include <rpc/rpc.h>
1044  #include <rpcsvc/yp_prot.h>
1045  #include <rpcsvc/ypclnt.h>
1046 -
1047 +#include <signal.h>
1048 +#include <linux/limits.h>
1049 +#include <sys/wait.h>
1050 +static int selinux_enabled=-1;
1051 +#ifdef WITH_SELINUX
1052 +#include <selinux/selinux.h>
1053 +static security_context_t prev_context=NULL;
1054 +#define SELINUX_ENABLED (selinux_enabled != -1 ? selinux_enabled : selinux_enabled=is_selinux_enabled())
1055 +#else
1056 +#define SELINUX_ENABLED 0
1057 +#endif
1058 +    
1059  #ifdef HAVE_CRACK_H
1060  #include <crack.h>
1061  #endif
1062 @@ -260,6 +271,97 @@
1063         return master;
1064  }
1065  
1066 +static int _unix_run_shadow_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user, const char *fromwhat, const char *towhat)
1067 +{
1068 +    int retval, child, fds[2];
1069 +    void (*sighandler)(int) = NULL;
1070 +
1071 +    D(("called."));
1072 +    /* create a pipe for the password */
1073 +    if (pipe(fds) != 0) {
1074 +       D(("could not make pipe"));
1075 +       return PAM_AUTH_ERR;
1076 +    }
1077 +
1078 +    if (off(UNIX_NOREAP, ctrl)) {
1079 +       /*
1080 +        * This code arranges that the demise of the child does not cause
1081 +        * the application to receive a signal it is not expecting - which
1082 +        * may kill the application or worse.
1083 +        *
1084 +        * The "noreap" module argument is provided so that the admin can
1085 +        * override this behavior.
1086 +        */
1087 +       sighandler = signal(SIGCHLD, SIG_DFL);
1088 +    }
1089 +
1090 +    /* fork */
1091 +    child = fork();
1092 +    if (child == 0) {
1093 +        int i=0;
1094 +        struct rlimit rlim;
1095 +       static char *envp[] = { NULL };
1096 +       char *args[] = { NULL, NULL, NULL, NULL };
1097 +
1098 +       /* XXX - should really tidy up PAM here too */
1099 +
1100 +       close(0); close(1);
1101 +       /* reopen stdin as pipe */
1102 +       close(fds[1]);
1103 +       dup2(fds[0], STDIN_FILENO);
1104 +
1105 +       if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
1106 +         for (i=2; i < rlim.rlim_max; i++) {
1107 +               if (fds[0] != i)
1108 +                  close(i);
1109 +         }     
1110 +       }
1111 +       /* exec binary helper */
1112 +       args[0] = x_strdup(CHKPWD_HELPER);
1113 +       args[1] = x_strdup(user);
1114 +       args[2] = x_strdup("shadow");
1115 +
1116 +       execve(CHKPWD_HELPER, args, envp);
1117 +
1118 +       /* should not get here: exit with error */
1119 +       D(("helper binary is not available"));
1120 +       exit(PAM_AUTHINFO_UNAVAIL);
1121 +    } else if (child > 0) {
1122 +       /* wait for child */
1123 +       /* if the stored password is NULL */
1124 +        int rc=0;
1125 +       if (fromwhat) 
1126 +         write(fds[1], fromwhat, strlen(fromwhat)+1);
1127 +       else
1128 +         write(fds[1], "", 1);
1129 +       if (towhat) {
1130 +         write(fds[1], towhat, strlen(towhat)+1);
1131 +       }
1132 +       else
1133 +         write(fds[1], "", 1);
1134 +
1135 +       close(fds[0]);       /* close here to avoid possible SIGPIPE above */
1136 +       close(fds[1]);
1137 +       rc=waitpid(child, &retval, 0);  /* wait for helper to complete */
1138 +       if (rc<0) {
1139 +         _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
1140 +         retval = PAM_AUTH_ERR;
1141 +       } else {
1142 +         retval = WEXITSTATUS(retval);
1143 +       }
1144 +    } else {
1145 +       D(("fork failed"));
1146 +       close(fds[0]);
1147 +       close(fds[1]);
1148 +       retval = PAM_AUTH_ERR;
1149 +    }
1150 +
1151 +    if (sighandler != NULL) {
1152 +        (void) signal(SIGCHLD, sighandler);   /* restore old signal handler */
1153 +    }
1154 +
1155 +    return retval;
1156 +}
1157  static int check_old_password(const char *forwho, const char *newpass)
1158  {
1159         static char buf[16384];
1160 @@ -318,16 +420,41 @@
1161      }
1162  
1163         oldmask = umask(077);
1164 +       
1165 +       if (SELINUX_ENABLED) {
1166 +               security_context_t passwd_context = NULL;
1167 +               
1168 +               if (getfilecon("/etc/passwd",&passwd_context) < 0) {
1169 +                       return PAM_AUTHTOK_ERR;
1170 +               }
1171 +               
1172 +               if (getfscreatecon(&prev_context)<0) {
1173 +                       freecon(passwd_context);
1174 +                       return PAM_AUTHTOK_ERR;
1175 +               }
1176 +               
1177 +               if (setfscreatecon(passwd_context)) {
1178 +                       freecon(passwd_context);
1179 +                       freecon(prev_context);
1180 +                       return PAM_AUTHTOK_ERR;
1181 +               }
1182 +               
1183 +               freecon(passwd_context);
1184 +       }
1185 +
1186         pwfile = fopen(OPW_TMPFILE, "w");
1187         umask(oldmask);
1188 -    if (pwfile == NULL) {
1189 -               return PAM_AUTHTOK_ERR;
1190 -    }
1191 +    
1192 +       if (pwfile == NULL) {
1193 +           err = 1;
1194 +           goto done;
1195 +       }
1196  
1197         opwfile = fopen(OLD_PASSWORDS_FILE, "r");
1198         if (opwfile == NULL) {
1199 -               fclose(pwfile);
1200 -               return PAM_AUTHTOK_ERR;
1201 +               fclose(pwfile);
1202 +               err=1;
1203 +               goto done;
1204         }
1205  
1206         chown(OPW_TMPFILE, 0, 0);
1207 @@ -388,8 +515,20 @@
1208                 err = 1;
1209         }
1210  
1211 -       if (!err) {
1212 +done:
1213 +       if (!err)
1214                 rename(OPW_TMPFILE, OLD_PASSWORDS_FILE);
1215 +#ifdef WITH_SELINUX
1216 +       if (SELINUX_ENABLED) {
1217 +           if (setfscreatecon(prev_context)) {
1218 +               err = 1;
1219 +           }
1220 +           if (prev_context)
1221 +               freecon(prev_context);
1222 +           prev_context=NULL;
1223 +       }
1224 +#endif
1225 +       if (!err) {
1226                 return PAM_SUCCESS;
1227         } else {
1228                 unlink(OPW_TMPFILE);
1229 @@ -406,16 +545,36 @@
1230         int oldmask;
1231  
1232         oldmask = umask(077);
1233 +#ifdef WITH_SELINUX
1234 +       if (SELINUX_ENABLED) {
1235 +           security_context_t passwd_context=NULL;
1236 +           if (getfilecon("/etc/passwd",&passwd_context)<0) {
1237 +               return PAM_AUTHTOK_ERR;
1238 +           };
1239 +           if (getfscreatecon(&prev_context)<0) {
1240 +               freecon(passwd_context);
1241 +               return PAM_AUTHTOK_ERR;
1242 +           }
1243 +           if (setfscreatecon(passwd_context)) {
1244 +               freecon(passwd_context);
1245 +               freecon(prev_context);
1246 +               return PAM_AUTHTOK_ERR;
1247 +           }
1248 +           freecon(passwd_context);
1249 +       }
1250 +#endif
1251         pwfile = fopen(PW_TMPFILE, "w");
1252         umask(oldmask);
1253 -    if (pwfile == NULL) {
1254 -               return PAM_AUTHTOK_ERR;
1255 -    }
1256 +       if (pwfile == NULL) {
1257 +               err=1;
1258 +               goto done;
1259 +       }
1260  
1261         opwfile = fopen("/etc/passwd", "r");
1262         if (opwfile == NULL) {
1263 -               fclose(pwfile);
1264 -               return PAM_AUTHTOK_ERR;
1265 +               fclose(pwfile);       
1266 +               err = 1;
1267 +               goto done;
1268         }
1269  
1270         chown(PW_TMPFILE, 0, 0);
1271 @@ -447,9 +606,22 @@
1272                 err = 1;
1273         }
1274  
1275 +done:
1276         if (!err) {
1277                 rename(PW_TMPFILE, "/etc/passwd");
1278                 _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
1279 +       }
1280 +#ifdef WITH_SELINUX
1281 +       if (SELINUX_ENABLED) {
1282 +           if (setfscreatecon(prev_context)) {
1283 +               err = 1;
1284 +           }
1285 +           if (prev_context)
1286 +               freecon(prev_context);
1287 +           prev_context=NULL;
1288 +       }
1289 +#endif
1290 +       if (!err) {
1291                 return PAM_SUCCESS;
1292         } else {
1293                 unlink(PW_TMPFILE);
1294 @@ -465,20 +637,43 @@
1295         int oldmask;
1296  
1297         spwdent = getspnam(forwho);
1298 -    if (spwdent == NULL) {
1299 -               return PAM_USER_UNKNOWN;
1300 -    }
1301 +
1302 +       if (spwdent == NULL) {
1303 +           return PAM_USER_UNKNOWN;
1304 +       }
1305 +       
1306         oldmask = umask(077);
1307 +#ifdef WITH_SELINUX
1308 +       if (SELINUX_ENABLED) {
1309 +           security_context_t shadow_context=NULL;
1310 +           if (getfilecon("/etc/shadow",&shadow_context)<0) {
1311 +               return PAM_AUTHTOK_ERR;
1312 +           };
1313 +           if (getfscreatecon(&prev_context)<0) {
1314 +               freecon(shadow_context);
1315 +               return PAM_AUTHTOK_ERR;
1316 +           }
1317 +           if (setfscreatecon(shadow_context)) {
1318 +               freecon(shadow_context);
1319 +               freecon(prev_context);
1320 +               return PAM_AUTHTOK_ERR;
1321 +           }
1322 +           freecon(shadow_context);
1323 +       }
1324 +#endif
1325         pwfile = fopen(SH_TMPFILE, "w");
1326         umask(oldmask);
1327 -    if (pwfile == NULL) {
1328 -               return PAM_AUTHTOK_ERR;
1329 -    }
1330 +       
1331 +       if (pwfile == NULL) {
1332 +           err = 1;
1333 +           goto done;
1334 +       }
1335  
1336         opwfile = fopen("/etc/shadow", "r");
1337         if (opwfile == NULL) {
1338                 fclose(pwfile);
1339 -               return PAM_AUTHTOK_ERR;
1340 +               err = 1;
1341 +               goto done;
1342         }
1343  
1344         chown(SH_TMPFILE, 0, 0);
1345 @@ -508,8 +703,22 @@
1346                 err = 1;
1347         }
1348  
1349 +done:
1350         if (!err) {
1351                 rename(SH_TMPFILE, "/etc/shadow");
1352 +       }
1353 +#ifdef WITH_SELINUX
1354 +       if (SELINUX_ENABLED) {
1355 +           if (setfscreatecon(prev_context)) {
1356 +               err = 1;
1357 +           }
1358 +           if (prev_context)
1359 +               freecon(prev_context);
1360 +           prev_context=NULL;
1361 +       }
1362 +#endif
1363 +    
1364 +       if (!err) {
1365                 return PAM_SUCCESS;
1366         } else {
1367                 unlink(SH_TMPFILE);
1368 @@ -600,6 +809,8 @@
1369         }
1370         if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) {
1371                 retval = _update_shadow(forwho, towhat);
1372 +               if (retval != PAM_SUCCESS && SELINUX_ENABLED)
1373 +                       retval = _unix_run_shadow_binary(pamh, ctrl, forwho, fromwhat, towhat);
1374                 if (retval == PAM_SUCCESS)
1375                         retval = _update_passwd(pamh, forwho, "x");
1376         } else {
1377 @@ -609,7 +820,7 @@
1378         return retval;
1379  }
1380  
1381 -static int _unix_verify_shadow(const char *user, unsigned int ctrl)
1382 +static int _unix_verify_shadow(pam_handle_t *pamh, const char *user, unsigned int ctrl)
1383  {
1384         struct passwd *pwd = NULL;      /* Password and shadow password */
1385         struct spwd *spwdent = NULL;    /* file entries for the user */
1386 @@ -630,6 +841,8 @@
1387                 spwdent = getspnam(user);
1388                 endspent();
1389  
1390 +               if (spwdent == NULL && SELINUX_ENABLED ) 
1391 +                   spwdent = _unix_run_verify_binary(pamh, ctrl, user);
1392                 if (spwdent == NULL)
1393                         return PAM_AUTHINFO_UNAVAIL;
1394         } else {
1395 @@ -877,7 +1090,7 @@
1396                         _log_err(LOG_CRIT, pamh,
1397                                  "failed to set PAM_OLDAUTHTOK");
1398                 }
1399 -               retval = _unix_verify_shadow(user, ctrl);
1400 +               retval = _unix_verify_shadow(pamh,user, ctrl);
1401                 if (retval == PAM_AUTHTOK_ERR) {
1402                         if (off(UNIX__IAMROOT, ctrl))
1403                                 _make_remark(pamh, ctrl, PAM_ERROR_MSG,
1404 @@ -926,7 +1139,7 @@
1405  #endif
1406                         return retval;
1407                 }
1408 -               retval = _unix_verify_shadow(user, ctrl);
1409 +               retval = _unix_verify_shadow(pamh, user, ctrl);
1410                 if (retval != PAM_SUCCESS) {
1411                         _log_err(LOG_NOTICE, pamh, "user not authenticated 2");
1412  #ifdef USE_LCKPWDF
1413 diff -urN pam-pld-0.77.3.org/modules/pam_unix/support.c pam-pld-0.77.3/modules/pam_unix/support.c
1414 --- pam-pld-0.77.3.org/modules/pam_unix/support.c       2003-12-27 01:14:07.000000000 +0100
1415 +++ pam-pld-0.77.3/modules/pam_unix/support.c   2003-12-27 03:10:49.073523544 +0100
1416 @@ -13,11 +13,18 @@
1417  #include <pwd.h>
1418  #include <shadow.h>
1419  #include <limits.h>
1420 +#include <linux/limits.h>
1421  #include <utmp.h>
1422  #include <errno.h>
1423  #include <crypt.h>
1424  #include <signal.h>
1425 -
1426 +#ifdef WITH_SELINUX
1427 +#include <selinux/selinux.h>
1428 +#define SELINUX_ENABLED is_selinux_enabled()
1429 +#else
1430 +#define SELINUX_ENABLED 0
1431 +#endif
1432 +    
1433  #include "security/_pam_macros.h"
1434  #include "security/pam_modules.h"
1435  
1436 @@ -464,18 +471,32 @@
1437      /* fork */
1438      child = fork();
1439      if (child == 0) {
1440 +        int i=0;
1441 +        struct rlimit rlim;
1442         static char *envp[] = { NULL };
1443 -       char *args[] = { NULL, NULL, NULL };
1444 +       char *args[] = { NULL, NULL, NULL, NULL };
1445  
1446         /* XXX - should really tidy up PAM here too */
1447  
1448 +       close(0); close(1);
1449         /* reopen stdin as pipe */
1450         close(fds[1]);
1451         dup2(fds[0], STDIN_FILENO);
1452  
1453 +       if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
1454 +         for (i=2; i < rlim.rlim_max; i++) {
1455 +               if (fds[0] != i)
1456 +                  close(i);
1457 +         }     
1458 +       }
1459         /* exec binary helper */
1460         args[0] = x_strdup(CHKPWD_HELPER);
1461         args[1] = x_strdup(user);
1462 +       if (off(UNIX__NONULL, ctrl)) {  /* this means we've succeeded */
1463 +         args[2]=x_strdup("nullok");
1464 +       } else {
1465 +         args[2]=x_strdup("nonull");
1466 +       }
1467  
1468         execve(CHKPWD_HELPER, args, envp);
1469  
1470 @@ -485,11 +506,7 @@
1471      } else if (child > 0) {
1472         /* wait for child */
1473         /* if the stored password is NULL */
1474 -       if (off(UNIX__NONULL, ctrl)) {  /* this means we've succeeded */
1475 -           write(fds[1], "nullok\0\0", 8);
1476 -       } else {
1477 -           write(fds[1], "nonull\0\0", 8);
1478 -       }
1479 +        int rc=0;
1480         if (passwd != NULL) {            /* send the password to the child */
1481             write(fds[1], passwd, strlen(passwd)+1);
1482             passwd = NULL;
1483 @@ -498,10 +515,17 @@
1484         }
1485         close(fds[0]);       /* close here to avoid possible SIGPIPE above */
1486         close(fds[1]);
1487 -       (void) waitpid(child, &retval, 0);  /* wait for helper to complete */
1488 -       retval = (retval == 0) ? PAM_SUCCESS:PAM_AUTH_ERR;
1489 +       rc=waitpid(child, &retval, 0);  /* wait for helper to complete */
1490 +       if (rc<0) {
1491 +         _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
1492 +         retval = PAM_AUTH_ERR;
1493 +       } else {
1494 +         retval = WEXITSTATUS(retval);
1495 +       }
1496      } else {
1497         D(("fork failed"));
1498 +       close(fds[0]);
1499 +       close(fds[1]);
1500         retval = PAM_AUTH_ERR;
1501      }
1502  
1503 @@ -523,6 +547,7 @@
1504         char *data_name;
1505         int retval;
1506  
1507 +
1508         D(("called"));
1509  
1510  #ifdef HAVE_PAM_FAIL_DELAY
1511 @@ -589,7 +614,7 @@
1512  
1513         retval = PAM_SUCCESS;
1514         if (pwd == NULL || salt == NULL || !strcmp(salt, "x")) {
1515 -               if (geteuid()) {
1516 +               if (geteuid() || SELINUX_ENABLED) {
1517                         /* we are not root perhaps this is the reason? Run helper */
1518                         D(("running helper binary"));
1519                         retval = _unix_run_helper_binary(pamh, p, ctrl, name);
1520 diff -urN pam-pld-0.77.3.org/modules/pam_unix/support.h pam-pld-0.77.3/modules/pam_unix/support.h
1521 --- pam-pld-0.77.3.org/modules/pam_unix/support.h       2003-12-27 01:14:07.000000000 +0100
1522 +++ pam-pld-0.77.3/modules/pam_unix/support.h   2003-12-27 01:14:20.000000000 +0100
1523 @@ -147,5 +147,6 @@
1524                         ,const char *data_name
1525                         ,const char **pass);
1526  
1527 +extern struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user);
1528  #endif /* _PAM_UNIX_SUPPORT_H */
1529  
1530 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
1531 --- pam-pld-0.77.3.org/modules/pam_unix/unix_chkpwd.c   2003-12-27 01:14:07.000000000 +0100
1532 +++ pam-pld-0.77.3/modules/pam_unix/unix_chkpwd.c       2003-12-27 02:58:53.004382600 +0100
1533 @@ -27,13 +27,24 @@
1534  #include <syslog.h>
1535  #include <unistd.h>
1536  #include <sys/types.h>
1537 +#include <sys/stat.h>
1538  #include <pwd.h>
1539  #include <shadow.h>
1540  #include <signal.h>
1541  #include <crypt.h>
1542 -
1543 +#include <time.h>
1544 +static int selinux_enabled=-1;
1545 +#ifdef WITH_SELINUX
1546 +#include <selinux/selinux.h>
1547 +#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : selinux_enabled=is_selinux_enabled())
1548 +static security_context_t prev_context=NULL;
1549 +#else
1550 +#define SELINUX_ENABLED 0
1551 +#endif
1552 +    
1553  #define MAXPASS                200     /* the maximum length of a password */
1554  
1555 +#include <security/_pam_types.h>
1556  #include "security/_pam_macros.h"
1557  
1558  #include "pam_crypt.h"
1559 @@ -86,6 +97,33 @@
1560         (void) sigaction(SIGQUIT, &action, NULL);
1561  }
1562  
1563 +static int _verify_account(const char * const uname)
1564 +{
1565 +       struct spwd *spent;
1566 +       struct passwd *pwent;
1567 +   
1568 +       pwent = getpwnam(uname);
1569 +       if (!pwent) {
1570 +           _log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname);
1571 +           return PAM_USER_UNKNOWN;
1572 +       }
1573 +  
1574 +       spent = getspnam( uname );
1575 +       if (!spent) {
1576 +           _log_err(LOG_ALERT, "could not get username from shadow (%s))", uname);
1577 +           return PAM_AUTHINFO_UNAVAIL;    /* Couldn't get username from shadow */
1578 +       }
1579 +       printf("%ld:%ld:%ld:%ld:%ld:%ld",
1580 +               spent->sp_lstchg, /* last password change */
1581 +               spent->sp_min, /* days until change allowed. */
1582 +               spent->sp_max, /* days before change required */
1583 +               spent->sp_warn, /* days warning for expiration */
1584 +               spent->sp_inact, /* days before account inactive */
1585 +               spent->sp_expire); /* date when account expires */
1586 +       
1587 +       return PAM_SUCCESS;
1588 +}
1589 +
1590  static int _unix_verify_password(const char *name, const char *p, int opt)
1591  {
1592         struct passwd *pwd = NULL;
1593 @@ -223,11 +261,171 @@
1594         return username;
1595  }
1596  
1597 + #define SH_TMPFILE            "/etc/nshadow"
1598 + static int _update_shadow(const char *forwho)
1599 + {
1600 +     struct spwd *spwdent = NULL, *stmpent = NULL;
1601 +     FILE *pwfile, *opwfile;
1602 +     int err = 1;
1603 +     int oldmask;
1604 +     struct stat st;
1605 +     char pass[MAXPASS + 1];
1606 +     char towhat[MAXPASS + 1];
1607 +     int npass=0;
1608 +
1609 +     /* read the password from stdin (a pipe from the pam_unix module) */
1610 +
1611 +     npass = read(STDIN_FILENO, pass, MAXPASS);
1612 +
1613 +     if (npass < 0) {  /* is it a valid password? */
1614 +
1615 +       _log_err(LOG_DEBUG, "no password supplied");
1616 +       return PAM_AUTHTOK_ERR;
1617 +
1618 +     } else if (npass >= MAXPASS) {
1619 +
1620 +       _log_err(LOG_DEBUG, "password too long");
1621 +       return PAM_AUTHTOK_ERR;
1622 +
1623 +     } else {
1624 +       /* does pass agree with the official one? */
1625 +       int retval=0;
1626 +       pass[npass] = '\0';     /* NUL terminate */
1627 +       retval = _unix_verify_password(forwho, pass, 0);
1628 +       if (retval != PAM_SUCCESS) {
1629 +       return retval;
1630 +       }
1631 +     }
1632 +
1633 +     /* read the password from stdin (a pipe from the pam_unix module) */
1634 +
1635 +     npass = read(STDIN_FILENO, towhat, MAXPASS);
1636 +
1637 +     if (npass < 0) {  /* is it a valid password? */
1638 +
1639 +       _log_err(LOG_DEBUG, "no new password supplied");
1640 +       return PAM_AUTHTOK_ERR;
1641 +
1642 +     } else if (npass >= MAXPASS) {
1643 +
1644 +       _log_err(LOG_DEBUG, "new password too long");
1645 +       return PAM_AUTHTOK_ERR;
1646 +
1647 +     }
1648 +
1649 +     towhat[npass] = '\0';     /* NUL terminate */
1650 +     spwdent = getspnam(forwho);
1651 +     if (spwdent == NULL) {
1652 +       return PAM_USER_UNKNOWN;
1653 +     }
1654 +     oldmask = umask(077);
1655 +
1656 + #ifdef WITH_SELINUX
1657 +     if (SELINUX_ENABLED) {
1658 +       security_context_t shadow_context=NULL;
1659 +       if (getfilecon("/etc/shadow",&shadow_context)<0) {
1660 +       return PAM_AUTHTOK_ERR;
1661 +       };
1662 +       if (getfscreatecon(&prev_context)<0) {
1663 +       freecon(shadow_context);
1664 +       return PAM_AUTHTOK_ERR;
1665 +       }
1666 +       if (setfscreatecon(shadow_context)) {
1667 +       freecon(shadow_context);
1668 +       freecon(prev_context);
1669 +       return PAM_AUTHTOK_ERR;
1670 +       }
1671 +       freecon(shadow_context);
1672 +     }
1673 + #endif
1674 +     pwfile = fopen(SH_TMPFILE, "w");
1675 +     umask(oldmask);
1676 +     if (pwfile == NULL) {
1677 +       err = 1;
1678 +       goto done;
1679 +     }
1680 +
1681 +     opwfile = fopen("/etc/shadow", "r");
1682 +     if (opwfile == NULL) {
1683 +       fclose(pwfile);
1684 +       err = 1;
1685 +       goto done;
1686 +     }
1687 +
1688 +     if (fstat(fileno(opwfile), &st) == -1) {
1689 +       fclose(opwfile);
1690 +       fclose(pwfile);
1691 +       err = 1;
1692 +       goto done;
1693 +     }
1694 +
1695 +     if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
1696 +       fclose(opwfile);
1697 +       fclose(pwfile);
1698 +       err = 1;
1699 +       goto done;
1700 +     }
1701 +     if (fchmod(fileno(pwfile), st.st_mode) == -1) {
1702 +       fclose(opwfile);
1703 +       fclose(pwfile);
1704 +       err = 1;
1705 +       goto done;
1706 +     }
1707 +     stmpent = fgetspent(opwfile);
1708 +     while (stmpent) {
1709 +
1710 +       if (!strcmp(stmpent->sp_namp, forwho)) {
1711 +           stmpent->sp_pwdp = towhat;
1712 +           stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
1713 +           err = 0;
1714 +           D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
1715 +       }
1716 +
1717 +       if (putspent(stmpent, pwfile)) {
1718 +           D(("error writing entry to shadow file: %s\n", strerror(errno)));
1719 +           err = 1;
1720 +           break;
1721 +       }
1722 +
1723 +       stmpent = fgetspent(opwfile);
1724 +     }
1725 +     fclose(opwfile);
1726 +
1727 +     if (fclose(pwfile)) {
1728 +       D(("error writing entries to shadow file: %s\n", strerror(errno)));
1729 +       err = 1;
1730 +     }
1731 +
1732 +  done:
1733 +     if (!err) {
1734 +       rename(SH_TMPFILE, "/etc/shadow");
1735 +     }
1736 +
1737 + #ifdef WITH_SELINUX
1738 +     if (SELINUX_ENABLED) {
1739 +       if (setfscreatecon(prev_context)) {
1740 +       err = 1;
1741 +       }
1742 +       if (prev_context)
1743 +       freecon(prev_context);
1744 +       prev_context=NULL;
1745 +     }
1746 + #endif
1747 +
1748 +     if (!err) {
1749 +       return PAM_SUCCESS;
1750 +     } else {
1751 +       unlink(SH_TMPFILE);
1752 +       return PAM_AUTHTOK_ERR;
1753 +     }
1754 + }
1755 +
1756 +
1757  int main(int argc, char *argv[])
1758  {
1759         char pass[MAXPASS + 1];
1760 -       char option[8];
1761         int npass, opt;
1762 +       char *option;
1763         int force_failure = 0;
1764         int retval = UNIX_FAILED;
1765         char *user;
1766 @@ -246,8 +444,7 @@
1767          * account).
1768          */
1769  
1770 -       if (isatty(STDIN_FILENO)) {
1771 -
1772 +       if (isatty(STDIN_FILENO) || argc != 3 ) {
1773                 _log_err(LOG_NOTICE
1774                       ,"inappropriate use of Unix helper binary [UID=%d]"
1775                          ,getuid());
1776 @@ -258,19 +455,43 @@
1777                 return UNIX_FAILED;
1778         }
1779  
1780 -       /*
1781 -        * determine the current user's name is
1782 -        */
1783 -       user = getuidname(getuid());
1784 -       if (argc == 2) {
1785 -           /* if the caller specifies the username, verify that user
1786 -              matches it */
1787 -           if (strcmp(user, argv[1])) {
1788 -               force_failure = 1;
1789 -           }
1790 -       }
1791 +       /*
1792 +        * determine the current user's name is.
1793 +        * On a SELinux enabled system, policy will prevent third parties from using
1794 +        * unix_chkpwd as a password guesser.  Leaving the existing check prevents
1795 +        * su from working,  Since the current uid is the users and the password is
1796 +        * for root.
1797 +         */
1798 +       if (SELINUX_ENABLED) {
1799 +         user=argv[1];
1800 +       }
1801 +       else {
1802 +         user = getuidname(getuid());
1803 +         /* if the caller specifies the username, verify that user
1804 +            matches it */
1805 +         if (strcmp(user, argv[1])) {
1806 +           return UNIX_FAILED;
1807 +         }
1808 +        }
1809 +
1810 +       option=argv[2];
1811 +
1812 +       if (strncmp(argv[2], "verify", 8) == 0) {
1813 +         /* Get the account information from the shadow file */
1814 +         return _verify_account(argv[1]);
1815 +       }
1816 +
1817 +       if (strncmp(option, "shadow", 8) == 0) {
1818 +         /* Attempting to change the password */
1819 +         return _update_shadow(argv[1]);
1820 +        }
1821 +       /* read the nullok/nonull option */
1822 +       if (strncmp(option, "nullok", 8) == 0)
1823 +         nullok = 1;
1824 +       else
1825 +         nullok = 0;
1826  
1827 -       /* read the nullok/nonull option */
1828 +        /* read the password from stdin (a pipe from the pam_unix module) */
1829  
1830         npass = read(STDIN_FILENO, option, 8);
1831  
This page took 0.183855 seconds and 4 git commands to generate.